[스프링 AOP 동작 원리] 빈 후처리기(feat.스프링이 제공하는 빈 후처리기)
간단하게 표현해서 빈 등록과정을 조작하는 것이다.
이것은 스프링 빈 객체를 조작하거나 심지어 다른 객체로 바꾸어 버릴 수 있을 정도로 막강하다
이 말은 스프링 빈 객체를 프록시로 교체하는 것도 가능하다는 뜻이다
스프링이 제공하는 BeanPostProcessor 인터페이스를 구현해서 만든다.
빈 후처리기를 사용하려면 BeanPostProcessor 인터페이스를 구현하고, 스프링 빈으로 등록하면 된다.
postProcessBeforeInitialization: 객체 생성 이후에 @PostConstruct 같은 초기화가 발생하기 전에 호출되는 포스트 프로세서이다.
postProcessAfterInitialization: 객체 생성 이후에 @PostConstruct 같은 초기화가 발생한 다음에 호출되는 포스트 프로세서이다.
빈 후처리기 적용 시점을 결정 할 수 있다.
정리
프록시 패턴
을 이용해서 핵심 로직으로 부터 서브 로직을 분리했고, 스프링이 제공하는 동적 프록시 기술인 프록시 팩토리
를 이용해서 중복코드를 제거했다.
마지막으로 빈 후처리기
를 이용해 컴포넌트 스캔으로 자동 등록된 본 객체를 프록시 객체로 바꿔치기함으로써 프록시를 효율적으로 사용할수있게 되었다.
하지만 개발자의 욕심은 끝이 없다.
스프링은 프록시를 생성하기 위한 전용 빈 후처리기를 이미 만들어서 제공한다.
스프링이 제공하는 빈 후처리기
implementation 'org.springframework.boot:spring-boot-starter-aop'
위 라이브러리를 추가하면 AOP 관련 클래스를 자동으로 스프링 빈에 등록한다.
AnnotationAwareAspectJAutoProxyCreator 라는 빈 후처리기가 스프링 빈에 자동으로 등록된다.
이름 그대로 자동으로 프록시를 생성해주는 빈 후처리기이다.
개발자는 빈 후처리기를 따로 정의할 필요가 없다.
AnnotationAwareAspectJAutoProxyCreator 의 동작 과정을 살펴보자.
1. 생성: 스프링이 스프링 빈 대상이 되는 객체를 생성한다. ( @Bean , 컴포넌트 스캔 모두 포함)
2. 전달: 생성된 객체를 빈 저장소에 등록하기 직전에 빈 후처리기에 전달한다.
3. 모든 Advisor 빈 조회: 자동 프록시 생성기 - 빈 후처리기는 스프링 컨테이너에서 모든 Advisor 를 조회한다.
4. 프록시 적용 대상 체크: 앞서 조회한 Advisor 에 포함되어 있는 포인트컷을 사용해서 해당 객체가 프록시를 적용할 대상인지 아닌지 판단한다. 이때 객체의 클래스 정보는 물론이고, 해당 객체의 모든 메서드를 포인트컷에 하나하나 모두 매칭해본다. 그래서 조건이 하나라도 만족하면 프록시 적용 대상이 된다. 예를 들어서 10개의 메서드 중에 하나만 포인트컷 조건에 만족해도 프록시 적용 대상이 된다.
5. 프록시 생성: 프록시 적용 대상이면 프록시를 생성하고 반환해서 프록시를 스프링 빈으로 등록한다. 만약
프록시 적용 대상이 아니라면 원본 객체를 반환해서 원본 객체를 스프링 빈으로 등록한다.
6. 빈 등록: 반환된 객체는 스프링 빈으로 등록된다.
3번을 살펴보면 모든 Advisor 빈을 조회한다는것을 알수있다.
즉, 개발자는 Advisor 만 빈에 등록해두면 프록시를 사용할 수 있다.
Advisor는 PointCut 과 Advice를 보유하고있기때문에 어떤 객체에 어떤 기능을 가진 프록시를 생성할지 알수있는것이다.
이때 여러개의 Advisor를 등록하더라도 같은 대상엔 하나의 프록시만 생성된다. Advisor당 프록시가 생성되는게 아니다.
프록시 팩토리가 생성하는 프록시는 내부에 여러 advisor 들을 포함할 수 있기 때문이다. 따라서 프록시를 여러 개 생성해서 비용을 낭비할 이유가없다.
@Aspect 애노테이션을 사용해서 더 편리하게 포인트컷과 어드바이스를 만들수있다.
@Component //빈 등록
@Aspect
public class LogTraceAdvisor {
private final LogTrace logTrace;
public LogTraceAdvisor(LogTrace logTrace) {
this.logTrace = logTrace;
}
@Around("execution(* PU.puservice..*(..))") //포인트 컷 AspectJ 사용
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable { //Advice
TraceStatus status = null;
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 의 값에 포인트컷 표현식을 넣는다. 표현식은 AspectJ 표현식을 사용한다.
@Around가 붙은 메서드가 어드바이스( Advice )가 된다.
@Component 를 이용해 어드바이저를 빈으로 등록한다.
ProceedingJoinPoint joinPoint 자바 리플랙션 기술을 활용해 실제 호출 대상,전달인자 등에 대한 메타정보를 담고있다.
정리
스프링이 제공하는 프록시 전용 빈 후처리기를 사용해 어드바이저만 등록하여 편리하게 프록시를 사용할수있다.
'개발자 준비 > Spring AOP' 카테고리의 다른 글
[Spring AOP 이론] 스프링 AOP! (0) | 2022.02.10 |
---|---|
[스프링 AOP 동작 원리] 프록시 팩토리 (0) | 2022.02.10 |
[스프링 AOP 동작 원리] 동적 프록시 (0) | 2022.02.10 |
[스프링 AOP 동작 원리] 프록시 (feat.완전한 서브로직 분리) (0) | 2022.02.10 |