@transactional @async 및 기타 주석이 작동하지 않습니다
이전에는 많은 사람들이 @transactional, @async 및 봄에 다른 주석을 사용할 때 주석이 작동하지 않는 상황을 만났습니다.
이러한 상황이 발생하는 이유는 무엇입니까? 이러한 주석의 기능은 실제로 Spring AOP에 의해 구현되며 구현 원칙은 프록시를 통해 구현됩니다.
JDK 동적 프록시
간단한 예를 들어 JDK Dynamic Proxy의 기본 원칙을 이해해 봅시다.
// 대상 클래스 인터페이스 공개 인터페이스 jdkproxyTestService {void run ();} // Target Class Public Class JDKProxyTestServiceImpl은 JDKPROXYTESTSERVICE {public void run () {System.out.println ( "Something ..."); }} // 프록시 클래스 공개 클래스 testjdkproxy는 invocationHandler {private 객체 targetObject; // 프록시 대상 객체 // 프록시 객체 구성 공개 객체 NewProxy (Object TargetObject) {this.targetObject = targetObject; return proxy.newproxyInstance (targetObject.getClass (). getClassLoader (), targetObject.getClass (). getInterfaces (), this); } // 반사를 사용하여 원래 논리에서 논리적 향상을 수행하기 위해 반사를 수행하십시오. // 원래 실행 로직 객체 ret = method.invoke (targetObject, args); // 모의 트랜잭션 제출 assumeCommitTransaction (); 반품 반환; } private void 가정 begintransaction () {system.out.println ( "모의 트랜잭션 시작 ..."); } private void AssumeCommitTransaction () {system.out.println ( "모의 트랜잭션 제출 ..."); }} // test public class test {public static void main (String [] args) {testjdkproxy jdkproxy = new testjdkproxy (); jdkproxytestservice proxy = (jdkproxytestservice) jdkproxy.newproxy (new jdkproxytestserviceimpl ()); proxy.run (); }}위의 예는 JDK 동적 프록시의 원리를 명확하게 설명 할 수 있어야합니다. 반사 메커니즘을 사용하여 프록시 인터페이스를 구현하는 익명 클래스를 생성하고 특정 메소드를 호출하기 전에 invokehandler를 호출합니다. 프록시 클래스 객체를 통해 메소드를 호출하면 실제로 호출 메소드를 호출 한 다음 원래 메소드를 호출합니다. 이러한 방식으로 원래 메소드 논리 전후에 처리 로직을 균일하게 추가 할 수 있습니다.
Spring은 또한 CGLIB Dynamic Proxy 인 동적 프록시 방법을 가지고 있습니다. 프록시 오브젝트 클래스의 클래스 파일을로드하고 바이트 코드를 수정하여 서브 클래스를 생성하여 처리합니다. 취급 방법은 다르지만 대행사의 아이디어는 일관성이 있습니다.
대상 대상 객체가 인터페이스를 구현하는 경우 Spring은 기본적으로 JDK Dynamic Proxy를 사용합니다. 이 대상 유형에서 구현 된 모든 인터페이스는 근접합니다. 대상 객체가 인터페이스를 구현하지 않으면 cglib 프록시가 생성됩니다.
스프링 AOP 주석 실패 및 해상도
동적 프록시 원리에 대한 위의 분석을 바탕으로 다음 두 가지 일반적인 문제를 살펴 보겠습니다.
동일한 클래스에서 메소드 A 호출 메소드 B (메소드 B에 주석이 붙어 있음) 및 주석이 유효하지 않습니다.
모든 스프링 AOP 주석의 경우, 스프링이 콩을 스캔 할 때 그러한 주석을 찾으면 프록시 객체를 동적으로 구성합니다.
이 주석은 클래스 X의 객체를 통해 A 메소드를 직접 호출하려는 경우 유효합니다. 이때 Spring은 호출하려는 메소드에 AOP 주석이 있다고 판단하고 클래스 X의 프록시 객체를 사용하여 메소드 A를 호출합니다.
그러나 클래스 X의 메소드 A가 주석을 사용하여 메소드 B를 호출한다고 가정하고 클래스 X의 객체를 통한 메소드를 호출하려고한다면 메소드 B의 주석이 유효하지 않다고 가정합니다. 스프링은 호출 호출에 주석이 없다고 판단하기 때문에 원래 객체는 프록시 객체보다는 여전히 사용됩니다. A가 다음으로 호출되면 원래 객체의 메소드 B의 주석이 물론 유효하지 않습니다.
해결책:
가장 쉬운 방법은 물론 A와 B가 종속성을 갖지 않으며 클래스 X의 객체를 통해 메소드 B를 직접 호출 할 수 있습니다.
그러나 여러 번, 우리의 논리는 이런 식으로 잘 쓰여지지 않을 수 있으므로 다른 방법이 있습니다 : 프록시 객체를 수동으로 얻는 방법을 찾으십시오.
AOPContext 클래스에는 현재 클래스의 프록시 객체를 직접 얻을 수있는 currentProxy () 메소드가 있습니다. 위의 예는 다음과 같이 해결할 수 있습니다.
// 메소드 B 내부 메소드 A // 1을 호출하십시오. B를 직접 호출하면 주석이 유효하지 않습니다. b () // 2. 프록시 클래스 객체를 받고 B를 호출합니다. ((x) aopContext.currentProxy ()). b ()
@autowired 객체는 AOP 주석 메소드에서 null입니다.
이전 사용에서, 주석 방법에서, 다른 주입 된 물체를 사용할 때, 물체가 주입되지 않았으며, 무효였다.
마지막으로, 그 이유는 방법이 비공개이기 때문입니다. Spring은 JDK Dynamic Proxy 또는 CGLIB Dynamic Proxy를 사용하기 때문에 하나는 인터페이스를 구현하고 다른 하나는 서브 클래스를 통해 구현되는 클래스입니다. 인터페이스 나 부모 클래스, 개인 메소드가 존재할 수 없으며, 그렇지 않으면 서브 클래스 나 구현 클래스를 무시할 수 없습니다.
방법이 비공개 인 경우 프록시 프로세스 에서이 방법을 찾을 수 없으므로 프록시 객체 생성에 문제가 발생하여 일부 객체를 주입하지 않습니다.
따라서 메소드가 AOP 주석을 사용해야하는 경우 비 개인적인 방법으로 설정하십시오.
위는이 기사의 모든 내용입니다. 모든 사람의 학습에 도움이되기를 바랍니다. 모든 사람이 wulin.com을 더 지원하기를 바랍니다.