스프링 어플리케이션에 프록시를 적용하려면 어드바이저를 스프링 빈으로 등록하면 된다.
이 전 글들에서 계속 언급돼 왔다시피 어드바이저 = 포인트컷 + 어드바이스 이다.
포인트컷: 적용 조건
어드바이스: 추가할 부가 기능
이 어드바이저를 등록하려면 긴 코드를 작성해줘야 했다.
하지만 우리의 스프링 부트는 이런 길고 반복되는 코드를 그냥 보고있지 않는다.
@Aspect 어노테이션은 이 반복되는 코드(어드바이저 등록)를 자동화해준다.
1. @Aspect 사용법
사용 방법은 너무나도 간단하다.
@Slf4j
@Aspect
public class LogTraceAspect {
private final LogTrace logTrace;
public LogTraceAspect(LogTrace logTrace) {
this.logTrace = logTrace;
}
@Around("execution(* hello.proxy.app..*(..))")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
TraceStatus status = null;
// log.info("target={}", joinPoint.getTarget()); //실제 호출 대상
// log.info("getArgs={}", joinPoint.getArgs()); //전달인자
// log.info("getSignature={}", joinPoint.getSignature()); //join point 시그니처
try {
String message = joinPoint.getSignature().toShortString();
status = logTrace.begin(message);
//로직 호출
Object result = joinPoint.proceed();
logTrace.end(status);
return result;
} catch (Exception e) {
logTrace.exception(status, e);
throw e;
}
}
}
@Aspect 어노테이션을 먼저 클래스에 붙여준다.
어드바이스로 만들 메소드 위에 @Around 어노테이션을 붙여준다.
@Around 어노테이션 안에는 포인트컷 표현식을 넣는데 이 표현식은 AspectJ 문법을 따른다.
ProceedingJoinPoint joinPoint 의 내부에는 실제 호출 대상, 전달 인자, 어떤 객체와 어떤 메소드가 호출되었는지 정보가 들어있다.
joinPoint.proceed() 로 실제 호출 대상인 target을 호출한다.
2. @Aspect 를 어드바이저로 변환해서 저장하는 과정
1) 실행: 스프링 애플리케이션 로딩 시점에 자동 프록시 생성기를 호출
2) 모든 @Aspect 빈 조회: 자동 프록시 생성기가 스프링 컨테이너에서 @Aspect 애노테이션이 붙은 스프링 빈을 모두 조회
3) 어드바이저 생성: @Aspect 어드바이저 빌더를 통해 @Aspect 어노테이션 정보를 기반으로 어드바이저를 생성
4) @Aspect 기반 어드바이저 저장: 생성한 어드바이저를 @Aspect 어드바이저 빌더 내부에 저장
3. 어드바이저를 기반으로 프록시 생성
1) 생성: 스프링 빈 대상이 되는 객체를 생성한다. ( @Bean , 컴포넌트 스캔 모두 포함)
2) 전달: 생성된 객체를 빈 저장소에 등록하기 직전에 빈 후처리기에 전달한다.
3-1) Advisor 빈 조회: 스프링 컨테이너에서 Advisor 빈을 모두 조회한다.
3-2) @Aspect Advisor 조회: @Aspect 어드바이저 빌더 내부에 저장된 Advisor 를 모두 조회한다.
4 부터는 기존에 공부했던 내용 그대로이다.
앞 단계가 추가되었다고 보면 된다.
4) 프록시 적용 대상 체크:
3-1, 3-2에서 조회한 Advisor 에 포함되어 있는 포인트컷을 사용해서 해당 객체가 프록시를 적용할 대상인지 아닌지 판단한다.
이때 객체의 클래스 정보는 물론이고, 해당 객체의 모든 메서드를 포인트컷에 하나하나 모두 매칭해본다.
그래서 조건이 하나라도 만족하면 프록시 적용 대상이 된다.
예를 들어서 메서드 하나만 포인트컷 조건에 만족해도 프록시 적용 대상이 된다.
5) 프록시 생성: 프록시 적용 대상이면 프록시를 생성하고 프록시를 반환한다.
그래서 프록시를 스프링 빈으로 등록한다.
만약 프록시 적용 대상이 아니라면 원본 객체를 반환해서 원본 객체를 스프링 빈으로 등록한다.
6) 빈 등록: 반환된 객체는 스프링 빈으로 등록된다.
'Spring > 이론' 카테고리의 다른 글
[스프링 고급] 빈 후처리기 (0) | 2024.01.23 |
---|---|
[스프링 기초] Bean, 의존성 주입 DI에 대한 나만의 고찰 (0) | 2024.01.23 |
[AOP 기반] 프록시 팩토리, 포인트컷, 어드바이스, 어드바이저란? (0) | 2024.01.17 |
프록시 형태 별 차이 (인터페이스 VS 클래스) (0) | 2024.01.04 |
[JPA] 응답 값으로 DTO를 전달해야 하는 이유 (0) | 2023.10.04 |