스프링 애플리케이션에 프록시를 적용하려면 포인트컷과 어드바이스로 구성되어있는 어드바이저를 만들어서 스프링빈으로 등록하면 됨. 나머지는 자동 프록시 생성기가 처리해주는 것 까지다뤘었다.
스프링이 지원해주는건 여기서 끝이 아니다. @Aspect 애너테이션을 이용해 포인트컷과 어드바이스로 구성되어있는 어드바이저를 더 쉽게 생성할 수 있다.
@Aspect 는 AOP라이브러리인 AspectJ에서 지원하는 애너테이션임. 스프링은 이걸 이용하고 있다. AOP와 AspectJ는 나중에 다시 더 다룰 것.
다음은 @Aspect + @Around 이용해 어드바이저를 만드는 코드이다.
@Aspect
@Slf4j
public class LogTraceAspect {
private final LogTrace logTrace;
public LogTraceAspect(LogTrace logTrace) {
this.logTrace = logTrace;
}
//@Around가 포인트 컷의 역할을 함.
//포인트컷이 적용된 메서드가 어드바이스의 역할을 함
@Around("execution(* hello.proxy.app..*(..))")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
//여기서부터 어드바이스 로직을 짜면 됨.
// 로그 추적 시작
TraceStatus status = null;
try {
// 로그 추적 시작
// Method method = invocation.getMethod();
// String message = method.getDeclaringClass().getSimpleName() + "."
// + method.getName();
// joinPoint를 통해 메서드 정보 가져오기
String message = joinPoint.getSignature().toShortString();
status = logTrace.begin(message);
// target의 핵심 로직 호출
//Object result = invocation.proceed();
// ProceedingJoinPoint를 사용하여 실제 메서드 호출
Object result = joinPoint.proceed();
logTrace.end(status);
return result;
} catch (Exception e){
log.error("Exception in LogTraceBasicHandler", e);
if (status != null) {
logTrace.exception(status, e);
}
throw e; // 예외를 다시 던져줘야 함
}
}
@Aspect 는 애노테이션기반 프록시를 사용할때 클래스에 붙여줌.
@Around 는 포인트컷의 표현식을 넣어주면 됨. 표현식은 AspectJ표현식을 사용함. @Around가 붙은 메서드는 어드바이스가 된다.
ProceedingJoinPoint 클래스는 이전에 Advice에서 살펴봤던 MethodInvocation 클래스와 유사한 기능을 한다.
기억이 안난다면 다음을 참고.
MethodInterceptor가 인자로 주입받는 클래스가MethodInvocation이다.
내부에 실제 호출 대상(target), 전달 인자(args), 그리고 추가 메타 정보들이 담겨있다.
joinPoint.proceed()를 통해 실제 호출대상의 메서드를 호출 할 수 있다.
위 클래스를 사용해보자. config파일을 만들어서 빈으로 등록해주면 된다.
@Configuration
@Import({AppV1Config.class, AppV2Config.class})
public class AopConfig {
@Bean
public LogTraceAspect logTraceAspect(LogTrace logTrace) {
return new LogTraceAspect(logTrace);
}
}