spring 에서 op 이 적용 되 지 않 는 몇 가지 해결 방법 을 상세 하 게 설명 합 니 다.

이 문제 의 배경 을 먼저 보 겠 습 니 다.spring 응용 프로그램 이 있다 고 가정 하고 개발 자 는 주석@Log 를 사용자 정의 하 기 를 원 합 니 다.지정 한 방법 에 추가 하여 자동 으로 로 그 를 기록 할 수 있 습 니 다(입 참,출 참,응답 시간 소모 등).

package com.cnblogs.yjmyzz.springbootdemo.aspect;
 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Log {
 
}
그 다음 에 Aspect 를 써 서 이 주 해 를 해석 하고 Log 주 해 를 하 는 방법 에 대해 강화 처 리 를 했 습 니 다.

package com.cnblogs.yjmyzz.springbootdemo.aspect;
 
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
 
import java.lang.reflect.Method;
 
@Component
@Aspect
public class LogAspect {
 
  @Pointcut("execution (* com.cnblogs.yjmyzz.springbootdemo.service..*.*(..))")
  public void logPointcut() {
 
  }
 
  @Around("logPointcut()")
  public void around(JoinPoint point) {
    String methodName = point.getSignature().getName();
    Object[] args = point.getArgs();
    Class<?>[] argTypes = new Class[point.getArgs().length];
    for (int i = 0; i < args.length; i++) {
      argTypes[i] = args[i].getClass();
    }
    Method method = null;
    try {
      method = point.getTarget().getClass().getMethod(methodName, argTypes);
    } catch (Exception e) {
      e.printStackTrace();
    }
    //        
    Log log = method.getAnnotation(Log.class);
    if (log != null) {
      //       ,      
      System.out.println("before:" + methodName);
    }
    try {
      //    
      ((ProceedingJoinPoint) point).proceed();
    } catch (Throwable throwable) {
      throwable.printStackTrace();
    } finally {
      if (log != null) {
        //       ,      
        System.out.println("after:" + methodName);
      }
    }
  }
}
테스트 Service 클래스 작성 하기:

package com.cnblogs.yjmyzz.springbootdemo.service;
 
import com.cnblogs.yjmyzz.springbootdemo.aspect.Log;
import org.springframework.stereotype.Component;
 
@Component
public class HelloService {
   
  @Log
  public void sayHi(String msg) {
    System.out.println("\tsayHi:" + msg);
  }
 
  public void anotherSayHi(String msg) {
    this.sayHi(msg);
  }
 
}
마지막 으로 한 판 뛰 자.

package com.cnblogs.yjmyzz.springbootdemo;
 
import com.cnblogs.yjmyzz.springbootdemo.service.HelloService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
 
/**
 * @author        
 */
@ComponentScan("com.cnblogs.yjmyzz")
@Configuration
@EnableAspectJAutoProxy
public class SampleApplication {
 
  public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SampleApplication.class);
    HelloService helloService = context.getBean(HelloService.class);
    helloService.sayHi("hi-1");
    System.out.println("
"); helloService.anotherSayHi("hi-2"); } }
출력 은 다음 과 같 습 니 다:

분명히 HelloService 의 anotherSay Hi 방법 은 op 에 의 해 강화 되 지 않 았 다.그 이 유 는 간단 하 다.AOP 의 원 리 를 아 는 학생 들 은 AOP 의 실현 은 두 가지 가 있다 는 것 을 알 고 있 을 것 이다.만약 에 인 터 페 이 스 를 바탕 으로 하 는 것 이 라면 동적 대 리 를 사용 하여 대리 류 를 생 성 할 것 이다.만약 에 클래스 를 바탕 으로 하 는 것 이 라면 CGLib 로 자 류 를 생 성 한 다음 에 하위 클래스 에서 부모 류 를 확장 하 는 방법 을 사용 할 것 이다.

본 논문 에서 HelloService 는 인터페이스 가 아니 기 때문에 위의 그림 의 정지점 에서 볼 수 있 듯 이 Spring 이 실 행 될 때 HelloService 는...Enhancerby SpringCGLib 로 증가 되 었 습 니 다.하지만 anotherSay Hi 로 호출 될 때

방법의 호출 자 는 원래 HelloSerfvice 인 스 턴 스 입 니 다.즉,Spring AOP 를 거치 지 않 은 대상 인 스 턴 스 입 니 다.그래서 문 제 를 해결 하 는 방향 이 생 겼 습 니 다.강 화 된 HelloService 인 스 턴 스 로 호출 할 방법 을 강구 하 세 요!
방법 1:Autowired 로 자신의 인 스 턴 스 를 주입 합 니 다.

이 방법 은 첫눈 에 이상 하 게 느껴 지고 자신 에 게 주입 되 며 약간 재 귀/사 순환 의 방법 처럼 느껴 지지 만 work 는 확실히 할 수 있 습 니 다.Spring 은 순환 의존 을 해결 하 는 데 자신의 처리 방식 이 있어 서 사 순환 을 피 할 수 있 습 니 다.
방법 2:Spring 컨 텍스트 에서 강 화 된 인 스 턴 스 참조 가 져 오기

원리 와 방법 은 사실 유사 하여 해석 이 많 지 않다.
방법 3:AopContext 이용

그러나 이 방법 은 주 클래스 입구 에 exporseProxy=true 를 추가 해 야 합 니 다.다음 그림 을 참고 하 십시오.

마지막 으로 이 세 가지 방법 이 효과 가 있 는 지 확인 합 니 다.

운행 결 과 를 보면 세 가지 방법 모두 이 문 제 를 해결 할 수 있다. 
여기 서 spring 에서 op 이 효력 이 발생 하지 않 는 몇 가지 해결 방법 에 대한 상세 한 설명 은 여기까지 입 니 다.더 많은 spring 에서 op 이 효력 이 발생 하지 않 는 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!
저자:보리수 아래 양 과
출처:http://yjmyzz.cnblogs.com

좋은 웹페이지 즐겨찾기