@Bean이나 컨포넌트 스캔으로 스프링빈을 등록하면, 스프링은 대상객체를 생성하고 스프링 컨테이너 내부의 빈 저장소에 등록을 한다.
그리고 이후에는 스프링 컨테이너를 통해 등록한 스프링빈을 조회해서 사용하면 된다.
스프링이 빈 저장소에 등록할 목적으로 생성한 객체를 빈 저장소에 등록하기 직전에 조작하고 싶다면 빈 후처리기를 사용하면 된다.
빈을 생성한 후에 무언가를 처리하는 용도로 사용한다.
객체를 조작할 수도 있고 완전히 다른객체로 바꿔치기 하는것도 가능하다.
A객체를 빈등록하고 빈후처리기에서 빈객체를 B객체로 바꿔치기를 해서 B객체를 등록시키도록한다.
@Slf4j
static class AToBPostProcessor implements BeanPostProcessor{
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
log.info("beanName={} bean={}",beanName,bean);
if(bean instanceof A){
return new B();
}
return bean;
}
}
해당 BeanPostProcessor을 스프링 빈으로 등록하기만하면 스프링컨테이너가 빈후처리로 인식하고 동작한다.
빈 후처리기는 빈을 조작하고 변경할 수 있는 후킹 포인트이다.
이것은 빈 객체를 조작하거나 심지 다른 객체로 바꾸어 버릴 수 있을 정도로 막강하다.
여기서 조작이라는 것은 해당 객체의 특정 매서드를 호출하는 것을 뜻한다.
일반적으로 스프링 컨테이너가 등록하는 특히 컨포넌트 스캔의 대상이 되는 빈들을 중간에 조작할 방법이 없는데 빈후처리기를 사용하면
개발자가 등록하는 모든 빈을 중간에 조작할 수 있다.
@PostConstruct는 스프링 빈 생성 이후에 빈을 초기화 하는 역할을 한다. 그런데 생각해보면
빈의 초기화 라는 것이 단순히 @PostConstruct이 붙은 초기화 메서드를 한번 호출만 하면된다.
쉽게 이야기 해서 생성된 빈을 한번 조작하는 것이다.
따라서 빈을 조작하는 행위를 하는 적절한 빈 후처리기가 있으면 될것같다.
스프링은 "CommonAnnotationBeanProcessor"라는 빈 후처리기를 자동으로 등록하는데 여기에서 @PostConstruct애노테이션이 붙은 메서드를 호출한다.
따라서 스프링 스스로도 스프링 내부에 기능을 확장하기 위해 빈 후처리기를 사용한다.
프록시의 적용 대상 여부를 패키지를 기준으로 설정했지만 포인트컷을 사용하면 더 깔끔하게 할수 있을것같다.
포인트컷은 이미 클래스 . 메서드 단위의 필터 기능을 가지고 있기 때문에, 프록시 적용 대상 여부를 정밀하게 설정할 수 있다.
참고로 어드바이저는 포인트 컷을 가지고 있다. 따라서 어드바이저를 통해 포인트 컷을 확인할 수 있다.
스프링 AOP는 포인트컷을 사용해서 프록시 적용 대상여부를 체크한다.
포인트컷이 사용되는 곳
1. 프록시 적용 대상여부를 체크해서 꼭 필요한 곳에만 프록시를 적용한다
2. 프록시의 어떤 메서가 호출되었을때 어드바이스를 적용할 지 판단한다.
implementation 'org.springframework.boot:spring-boot-starter-aop'
AnnotationAwareAspectAutoProxyCreator는 @AspectJ와 관련된 AOP기능도 자동으로 찾아서 처리해 준다.
Advisor는 물론이고 @Aspect도 자동으로 인식해서 프록시를 만들고 AOP를 적용해 준다.
자동 프록시 생성기의 작동과정
1. 생성: 스프링이 스프링 빈 대상이 되는 개체 생성
2. 전달: 생성된 객체를 빈 저장소에 등록하기 직전에 빈 후처리기전달
3. 모든 Advisor빈 조회: 자동 프록시 생성기-빈 후처리기는 스프링 컨테이너에서 모든 Advisor를 조회한다.
4. 프록시 적용 대상 체크 : 앞서 조회한 Advisor에 포함되어 있는 포인트컷을 사용해서 해당 객체가 프록시를 적용할 대상인지
아닌지 판단한다. 이때 객체의 클래스 정보는 물론이고 해당 객체의 모든 메서드를 포인트컷 하나하나 모두 매칭해 본다. 그래서 조건이 하나라도 만족하면
프록시 적용 대상이된다. 예를 들어 10개중에 하나만 만족돼도 프록시 적용대상이 되는것
5. 프록시 생성 프록시 적용 대상이면 프록시를 생성하고 반환해서 프록시를 스프링 빈으로 등록한다.
6. 빈등록 : 반환된 객체는 스프링빈으로 등록된다.
@Bean
public Advisor getAdvisor(LogTrace logTrace) {
//poincut
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.setMappedNames("request*" , "order*","save*");
LogTraceAdvice advice = new LogTraceAdvice(logTrace);
return new DefaultPointcutAdvisor(pointcut,advice);
}
위와 같이 Advisor만 빈에 등록되면 내부적으로 자동으로 작동된다.
AspectJ라는 AOP에 특화된 포인트컷 표현식을 적용할 수 있다.