오늘은 Spring AOP의 내부 메커니즘을 깊이 있게 파헤쳐보고, HttpRequestLoggingAdvice
클래스를 예제로 설명하겠습니다. 또한, AOP의 최적화 방식과 @RestControllerAdvice
가 왜 Spring의 AOP 방식과 다르게 동작하는지에 대해 알아보겠습니다 😊
AOP(Aspect-Oriented Programming)는 프로그램의 공통 관심사를 핵심 비즈니스 로직과 분리하여 모듈화하는 프로그래밍 패러다임입니다. 스프링 AOP는 프록시 패턴을 기반으로 메서드 실행 전후에 특정 부가 기능을 자동으로 적용할 수 있게 해줍니다.
Spring AOP는 몇 가지 핵심 구성 요소로 이루어져 있습니다. 이를 이해하면 HttpRequestLoggingAdvice
가 어떻게 동작하는지 쉽게 파악할 수 있습니다.
@Aspect
어노테이션을 사용하여 정의합니다.@Around
는 메서드 실행 전후에 로직을 실행할 수 있도록 합니다.Spring AOP는 두 가지 주요 프록시 메커니즘을 사용합니다: JDK 동적 프록시와 CGLIB 프록시. 각각의 특성과 사용 시점을 이해하는 것은 매우 중요합니다.
final
일 경우 프록시 생성이 불가능합니다.Spring AOP는 기본적으로 대상 빈이 하나 이상의 인터페이스를 구현하고 있으면 JDK 동적 프록시를 사용합니다. 그렇지 않거나, proxyTargetClass=true
로 설정된 경우 CGLIB 프록시를 사용합니다.
@Bean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
proxyCreator.setProxyTargetClass(false); // 인터페이스 기반 프록시 사용 (JDK 동적 프록시)
return proxyCreator;
}
HttpRequestLoggingAdvice
클래스 분석 📚이제 HttpRequestLoggingAdvice
클래스를 살펴보겠습니다. 이 클래스는 Spring AOP를 활용해 HTTP 요청을 로깅하는 역할을 합니다.
@Component
@Aspect
public class HttpRequestLoggingAdvice {
private static final Logger logger = LoggerFactory.getLogger(HttpRequestLoggingAdvice.class);
@Around("@within(com.jongho.common.annotaition.HttpRequestLogging)")
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().toShortString();
Object[] args = joinPoint.getArgs();
logger.info("Method: " + methodName + ", parameters: " + Arrays.toString(args));
return joinPoint.proceed();
}
}
@Component
: 이 클래스를 Spring의 빈으로 등록합니다.@Aspect
: 이 클래스가 AOP의 Aspect임을 나타냅니다.@Around
: 메서드 실행 전후에 특정 로직을 실행할 수 있는 어드바이스를 정의합니다.@within
: 특정 어노테이션이 적용된 클래스의 모든 메서드에 어드바이스를 적용합니다.ProceedingJoinPoint
: 실제 메서드를 호출하기 위해 proceed()
메서드를 제공합니다.HttpRequestLoggingAdvice
의 동작 과정 🔄이제 HttpRequestLoggingAdvice
클래스가 Spring AOP에서 어떻게 동작하는지 단계별로 살펴보겠습니다.
AnnotationConfigApplicationContext
가 AppConfig
및 기타 설정 클래스를 로드하여 빈을 정의하고 초기화합니다.@Component
어노테이션이 있는 HttpRequestLoggingAdvice
클래스가 스캔되어 빈으로 등록됩니다.HttpRequestLoggingAdvice
빈을 생성합니다.@Aspect
어노테이션을 통해 이 빈이 어스팩트로 등록됩니다. 스프링은 이 어스팩트를 감지하여 AOP 설정에 추가합니다.DefaultAdvisorAutoProxyCreator
의 역할 🤖DefaultAdvisorAutoProxyCreator
빈 등록: AppConfig
클래스에서 DefaultAdvisorAutoProxyCreator
빈이 정의되어 있습니다.
@Configuration
public class AppConfig {
@Bean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
proxyCreator.setProxyTargetClass(false); // 인터페이스 기반 프록시 사용 (JDK 동적 프록시)
return proxyCreator;
}
}
빈 후처리기 역할: DefaultAdvisorAutoProxyCreator
는 BeanPostProcessor로 동작하며, 빈이 초기화된 후에 AOP 어드바이저를 검색하고 프록시를 생성합니다.
DefaultAdvisorAutoProxyCreator
는 스프링 컨테이너 내의 모든 어드바이저 빈을 검색합니다. 여기서 HttpRequestLoggingAdvice
가 정의한 @Around
어드바이저가 포함됩니다.@HttpRequestLogging
어노테이션이 적용된 클래스의 모든 메서드가 포인트컷과 매칭됩니다.MyServiceImpl
)이 인터페이스(MyService
)를 구현하고 있으며, proxyTargetClass=false
로 설정되었기 때문에 JDK 동적 프록시가 생성됩니다.
4. 인터셉터 체인 설정: 매칭된 어드바이저의 어드바이스(LoggingInterceptor
)가 인터셉터 체인에 추가됩니다.
프록시 생성 과정에서 Spring AOP는 JDK 동적 프록시를 사용하여 대상 빈을 감싸는 프록시 객체를 생성합니다. 이 프록시는 대상 빈의 인터페이스를 구현하고, InvocationHandler를 통해 메서드 호출을 가로채어 인터셉터 체인을 실행합니다.
@RestControllerAdvice
의 독립성 🧩Spring AOP는 프록시 패턴을 기반으로 다양한 최적화 기법을 적용하여 성능을 향상시킵니다. 주요 최적화 방식은 다음과 같습니다:
@RestControllerAdvice
의 독립성@RestControllerAdvice
는 Spring MVC의 예외 처리 메커니즘을 활용하여 전역적인 예외 처리를 담당합니다. 이는 Spring AOP의 프록시 기반 메커니즘과는 별개로 동작합니다.
@RestControllerAdvice
는 예외 발생 시점에 개입하여 예외를 처리합니다.Spring MVC의 예외 처리 체인은 다음과 같이 구성됩니다:
컨트롤러 내부의 @ExceptionHandler
:
@ControllerAdvice
또는 @RestControllerAdvice
:
기본 예외 처리기:
이 체인은 AOP의 인터셉터 체인과는 별도로 동작하며, 예외 발생 시점에 개입하여 예외를 처리합니다.
이 포스트가 여러분의 Spring AOP와 @RestControllerAdvice
에 대한 이해에 도움이 되었길 바랍니다. 😊✨
더 궁금한 점이나 추가적인 설명이 필요하시면 댓글로 남겨주세요! 👍