참고자료
스프링 핵심 원리 - 고급편 강의 | 김영한 - 인프런
김영한 | 스프링의 핵심 원리와 고급 기술들을 깊이있게 학습하고, 스프링을 자신있게 사용할 수 있습니다., 핵심 디자인 패턴, 쓰레드 로컬, 스프링 AOP스프링의 3가지 핵심 고급 개념 이해하기
www.inflearn.com
@Aspect 프록시 - 적용
스프링 애플리케이션에 프록시를 적용하려면 포인트컷과 어드바이스로 구성되어 있는 어드바이저(Advisor)를 만들어서 스프링 빈으로 등록하면 된다. 그러면 나머지는 앞서 배운 AnnotationAwareAspectJAutoProxyCreator 가 모두 자동으로 처리해준다. AnnotationAwareAspectJAutoProxyCreator는 스프링 빈으로 등록된 어드바이저들을 찾고, 스프링 빈들에 자동으로 프록시를 적용해준다.
스프링은 @Aspect 애노테이션으로 매우 편리하게 포인트컷과 어드바이스로 구성되어 있는 어드바이저 생성 기능을 지원한다. 지금까지 어드바이저를 직접 만들었던 부분을 @Aspect 애노테이션을 사용해서 만들어보자. 그러니까, @Aspect를 사용해서 빈으로 등록한 것들도 저 AnnotationAwareAspectJAutoProxyCreator이 녀석이 다 찾아서 프록시 적용 여부를 확인하고 적용 대상에는 프록시를 입혀 빈으로 등록해준다.
참고로, @Aspect는 관점 지향 프로그래밍(AOP)을 가능하게 하는 AspectJ 프로젝트에서 제공하는 애노테이션이다. 스프링은 이것을 차용해서 프록시를 통한 AOP를 가능하게 한다. AOP와 AspectJ 관련된 자세한 내용은 이후에 나온다. 지금은 프록시에 초점을 맞추자. 우선 이 애노테이션을 사용해서 스프링이 편리하게 프록시를 만들어준다고 생각하면 된다.
LogTraceAspect
package cwchoiit.springadvanced.proxy.config.v6_aop.aspect;
import cwchoiit.springadvanced.trace.TraceStatus;
import cwchoiit.springadvanced.trace.logtrace.LogTrace;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@Slf4j
@Aspect
public class LogTraceAspect {
private final LogTrace trace;
public LogTraceAspect(LogTrace trace) {
this.trace = trace;
}
@Around("execution(* cwchoiit.springadvanced.proxy.app..*(..))")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
TraceStatus status = null;
Signature signature = joinPoint.getSignature();
try {
String message = signature.toShortString();
status = trace.begin(message);
Object result = joinPoint.proceed();
trace.end(status);
return result;
} catch (Exception e) {
trace.exception(status, e);
throw e;
}
}
}
- @Aspect → 애노테이션 기반 프록시를 적용할 때 필요하다.
- @Around("execution(* cwchoiit.springadvanced.proxy.app..*(..))")
- * → 모든 반환 타입을 의미. (원래 맨 앞에 접근 제어자가 가장 먼저인데 생략이 가능하다. 그래서 한 개만 있는 경우 반환 타입을 나타낸다)
- cwchoiit.springadvanced.proxy.app.. → cwchoiit.springadvanced.proxy.app 패키지와 그 하위 모든 패키지(..)를 나타낸다.
- *(..) → 모든 메서드(*)의 모든 파라미터(..)를 의미한다.
- 그래서 결론적으로 * cwchoiit.springadvanced.proxy.app..*(..) 은 해당 패키지부터 그 하위 모든 패키지의 모든 반환 타입의 모든 메서드의 어떠한 파라미터도 상관없이 해당되는 메서드들을 가리킨다.
- 그리고 해당 메서드의 파라미터를 보면 ProceedingJoinPoint joinpoint를 받는다. 이건 예전 포스팅에서 어드바이스를 만들 때 MethodInvocation invocation과 유사하다. 내부에 실제 호출 대상, 전달 인자, 그리고 어떤 객체와 어떤 메서드가 호출되었는지 정보가 포함되어 있다.
- 그래서 joinpoint.proceed()를 호출하는 게 실제 호출 대상(target)을 호출하는 것이다.
@Aspect 프록시 - 설명
우선 스프링의 AnnotationAwareAspectJAutoProxyCreator는 2가지 일을 한다.
- 스프링 빈으로 등록된 Advisor를 가져와서 프록시 적용 대상 판단 후 적용
- 스프링 빈으로 등록된 @Aspect를 보고 어드바이저로 변환하고 프록시 적용 대상 판단 후 적용
@Aspect 빈을 통해 어드바이저를 만드는 과정
1. 생성: 스프링이 빈으로 등록될 객체를 생성한다.(@Bean, 컴포넌트 스캔 모두 포함)
2. 전달: 생성된 객체를 빈 저장소에 등록하기 전 빈 후처리기에 전달한다.
3. 모든 Advisor 빈 조회: 스프링 컨테이너에서 Advisor 빈을 모두 조회한다.
3-1. 모든 @Aspect 빈 조회: @Aspect 어드바이저 빌더 내부에 저장된 Advisor를 모두 조회한다. (사실 이 과정 전에 먼저 빈으로 등록된 @Aspect 애노테이션이 달려있는 모든 클래스를 찾고 어드바이저로 만든 후 @Aspect 어드바이저 빌더에 저장하는 과정이 생략되어 있다)
4. 프록시 적용 대상 체크: 앞서 3, 3-1 에서 조회한 Advisor에 포함되어 있는 포인트컷을 사용해서 해당 객체가 프록시를 적용할 대상인지 아닌지 판단한다. 이 때 객체의 클래스 정보는 물론이고, 해당 객체의 모든 메서드를 포인트컷에 하나하나 모두 매칭해본다. 그래서 조건이 하나라도 만족하면 프록시 적용 대상이 된다. 예를 들어, 메서드 하나만 포인트컷 조건에 만족해도 프록시 적용 대상이 된다.
5. 프록시 생성: 프록시 적용 대상이면 프록시를 생성하고 프록시를 반환한다. 그래서 프록시를 스프링 빈으로 등록한다. 만약 프록시 적용 대상이 아니라면 원본 객체를 반환해서 원본 객체를 스프링 빈으로 등록한다.
6. 빈 등록: 반환된 객체는 스프링 빈으로 등록된다.
정리를 하자면
@Aspect를 사용해서 이전 작업과는 비교도 안되게 편리하게 프록시를 적용할 수 있다. @Aspect 애노테이션이 달린 클래스를 빈으로 등록하면 스프링이 자동으로 만들어주는 AnnotationAwareAspectJAutoProxyCreator 빈 후처리기를 통해 알아서 포인트컷의 조건을 기반으로 프록시를 만들어준다. 실무에서는 프록시를 적용하려고 하면 대부분 이 방식을 사용한다.
지금까지 우리가 진행한 애플리케이션 전반에 로그를 남기는 기능은 특정 기능 하나에 관심이 있는 기능이 아니다. 애플리케이션의 여러 기능들 사이에 걸쳐서 들어가는 공통 관심사이다. 이것을 바로 횡단 관심사(cross-cutting concerns)라고 한다. 우리가 지금까지 진행한 방법이 이렇게 여러곳에 걸쳐 있는 횡단 관심사의 문제를 해결하는 방법이었다.
지금까지 프록시를 사용해서 이렇게 횡단 관심사를 어떻게 해결하는지 점진적으로 매우 깊이있게 학습하고 기반을 다져두었다. 이제 이 기반을 바탕으로 이러한 횡단 관심사를 전문으로 해결하는 스프링 AOP에 대해 본격적으로 알아보자!
'Spring Advanced' 카테고리의 다른 글
스프링 AOP Part.2 (0) | 2024.01.02 |
---|---|
스프링 AOP Part. 1 (0) | 2023.12.29 |
빈 후처리기(BeanPostProcessor) (2) | 2023.12.27 |
Advisor, Advice, Pointcut (0) | 2023.12.15 |
CGLIB,스프링이 지원하는 ProxyFactory (0) | 2023.12.14 |