스프링 애플리케이션에 프록시를 적용하려면 포인트컷과 어드바이스로 구성되어있는 어드바이저를 만들어서 스프링빈으로 등록하면 됨. 나머지는 자동 프록시 생성기가 처리해주는 것 까지다뤘었다.
스프링이 지원해주는건 여기서 끝이 아니다. @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);
}
}