[Spring][AOP] 빈 후처리기, Aspect 프록시

donghyeok·2023년 3월 4일
0

Spring

목록 보기
5/9

빈 후처리기

앞서 프록시 관련 예제에서 특정 빈들에 대해 Advisor를 만들어 적용하는 것을 보았다.
하지만 앞선 예제들에서는 여러 문제들이 있었다.

  1. 너무 많은 설정
    프록시를 직접 스프링 빈으로 등록하는 설정 파일에서 프록시 관련 설정이 지나치게 많았다.
    예를 들어 스프링 빈이 100개 있다면 프록시를 통해 적용하기 위해 100개의 프록시 설정 코드가 필요했다.

  2. 컴포넌트 스캔
    스프링 빈을 컴포넌트 스캔을 사용하는 경우 프록시 적용이 불가능 했다. (이미 빈으로 등록되어 버림)
    스프링 컨테이너에 원본 객체의 프록시를 등록할 수 있는 방법이 없어 적용이 불가능했다.

빈 후처리기 사용

위와 같은 문제들은 위 그림처럼 동작하는 빈 후처리기를 통해 해결할 수 있다.
빈 후처리기 같은 경우 빈을 컨테이너에 등록하기 전에 후킹하여 프록시 객체로 바꿔치기하여
빈 등록이 가능하기 때문에 컴포넌트 스캔 방식에도 문제가 없고
관련 설정을 중복 코드 없이 빈 후처리기 코드만으로 끝낼 수 있다.

예제

@Slf4j
public class PackageLogTracePostProcessor implements BeanPostProcessor {

    private final String basePackage;
    private final Advisor advisor;

    public PackageLogTracePostProcessor(String basePackage, Advisor advisor) {
        this.basePackage = basePackage;
        this.advisor = advisor;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        log.info("param beanName={}, bean={}", beanName, bean);

        String packageName = bean.getClass().getPackageName();
        if (!packageName.startsWith(basePackage)) {
            return bean;
        }

        ProxyFactory proxyFactory = new ProxyFactory(bean);
        proxyFactory.addAdvisor(advisor);
        return proxyFactory.getProxy();
    }
}

위 코드처럼 빈 컨테이너에 등록전 가로채서 프록시 객체로 바꿔칠 수 있으며 패키지 경로로 선택적 교체가 가능하다.

포인트컷의 용도

위 예제에서는 프록시의 적용 대상 여부를 간단히 패키지 기준으로 설정했다.
하지만 이를 포인트컷을 사용하면 더 깔끔하다.
프인트컷은 이미 클래스, 메서드 단위의 필터 기능을 가지고 있기 때문에, 프록시 적용 대상 여부를 정밀하게 설정 가능하다.
스프링 AOP는 포인트컷을 사용해서 프록시 적용 대상 여부를 체크한다.

결과적으로 포인트컷은 다음 두 곳에서 사용된다.

1. 프록시 적용 대상 여부를 체크하기 위한 용도 (빈 후처리기)
2. 프록시의 어떤 메서드가 호출 될 때 어드바이스를 적용할지 체크 (프록시 내부) 

스프링이 제공하는 빈 후처리기

스프링에 `org.springframework.boot:spring-boot-starter-aop` 라이브러리를 추가하면 스프링 부트가 AOP 관련 클래스를 자동으로 스프링 빈에 등록한다.

이러한 부트의 자동 설정으로 AnnotationAspectJAutoProxyCreater라는 빈 후처리기가 스프링빈에 자동으로 등록된다.

이름 그대로 자동으로 프록시를 생성해주는 빈 후처리기이다.
해당 빈 후처리기는 스프링 빈으로 등록된 Advisor들을 자동으로 찾아서 프록시가 필요한 곳에 자동으로 프록시를 적용해준다.
Advisor 내부에는 포인트컷과 어드바이스가 모두 포함되어 있는데 포인트컷을 이용해 어떤 스프링 빈에 프록시를 적용할지를 판단한다.

@Aspect 프록시

앞서 스프링 애플리케이션에 프록시를 적용하기 위해 어드바이저를 만들고 스프링 빈으로 등록했다.
이를 더 편리하게 스프링은 @Aspect 애노테이션으로 매우 편리하게 포인트컷과 어드바이스로 구성되어 있는 어드바이저 생성 기능을 제공한다.

앞서 설명한 AnnotationAwareAspectJAutoProxyCreator는 어드바이저를 자동으로 찾아 필요한 곳에 프록시를 생성하고 적용해주는 기능 외에도 @Aspect를 찾아서 이것을 어드바이저로 만들고 저장해주는 기능도 수행한다.

@Aspect 구성

@Aspect 
public class LogTraceAspect {
	@Around("execution(* hello.proxy.app..*(..))")
    public Object execute(ProceedingJoinPoint joinPoint) {
    	//advice 로직
    }
}	

@Aspect로 어드바이저를 구성하는 방식은 위와 같다.
@Aspect 어드바이저 빌더는 위 코드를 어드바이저로 변환하는데 구성은 아래와 같다.
@Around(..) : 포인트컷을 의미하고 어느 위치에 프록시를 적용할지 정함.
메서드 : 어드바이스를 의미하고 실제 어드바이스 로직을 넣어준다.
위 클래스를 빈으로 등록해주면 자동 프록시 생성기는 어드바이저로 변환 후 저장해준다.

@Aspect 어드바이저 변환 및 저장 과정

@Aspect를 어드바이저로 변환해서 저장하는 과정은 다음과 같다.
1. 실행 : 스프링 어플리케이션 로딩 시점에 자동 프록시 생성기를 호출한다. 
2. 모든 @Aspect 빈 조회 : 자동 프록시 생성기는 해당 애노테이션이 붙은 스프링 빈을 모두 조회한다. 
3. 어드바이저 생성 : @Aspect 어드바이저 빌더를 통해 @Aspect 애노테이션 정보를 기반으로 어드바이저를 생성한다. 
4. @Aspect 기반 어드바이저 저장 : 생성한 어드바이저를 @Aspect 빌더 내부에 저장한다. 

0개의 댓글