스프링 부트 - 빈 후처리기와 프록시 자동 생성기

SeungTaek·2021년 11월 3일
0
post-thumbnail

본 게시물은 스스로의 공부를 위한 글입니다.
잘못된 내용이 있으면 댓글로 알려주세요!


📒 빈 후처리기

  • 일반적으로 스프링 빈을 등록할 때는 다음과 같은 로직이 실행된다.
    • 객체 생성 -> 스프링 컨테이너 빈 저장소에 등록
  • 빈 후처리기(BeanPostProcessor)을 사용하면 빈 저장소에 등록 직전에 조작할 수 있다.
    • 객체 생성 -> 빈 후처리기에 전달 -> 후 처리 작업 -> 빈 저장소에 등록
  • 빈 후처리기는 BeanPostProcessor을 구현하면 사용할 수 있다.
    • postProcessBeforeInitialization: 객체 생성 이후에 @PostConstruct같은 초기화가 발생하기 전에 호출되는 포스트 프로세서
    • postProcessAfterInitialization : 객체 생성 이후에 @PostConstruct 같은 초기화가 발생한 다음에 호출되는 포스트 프로세서

🎈 예시

@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;
    }
}
  • A 객체의 인스턴스가 빈으로 등록 시도를 하면 B 객체의 인스턴스로 바꿔치기 하는 코드이다.




📌 프록시에 활용

  • 빈 후처리기를 사용하면 개발자가 등록하는 모든 빈을 중간에 조작할 수 있다.
  • 즉, 빈 객체를 프록시로 교체하는 것도 가능하다는 뜻이다.

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

  • 먼저 이 기능을 사용하려면 다음의 디펜던시가 필요하다.

    • implementation 'org.springframework.boot:spring-boot-starter-aop'

    • aspectJ라는 라이브러리를 등록하고, 스프링 부트가 AOP 관련 클래스를 자동으로 스프링 빈에 등록한다.

  • 스프링 부트 자동 설정으로 AnnotationAwareAspectJAutoProxyCreator라는 빈 후처리기가 스프링 빈에 자동 등록된다.

    • 자동으로 프록시를 생성해주는 빈 후처리기이다.
    • 스프링 빈으로 등록된 Advisor들을 자동으로 찾아서 프록시가 필요한 곳에 자동으로 프록시를 적용해준다.
  • Advisor에는 Pointcut이 포함되어 있다. 즉, Pointcut의 정보로 [어떤 객체에], [어느 메소드에] 적용해야 하는지 알 수 있고, 그 정보를 바탕으로 프록시를 생성해준다.



🎈 자동 프록시 생성기의 작동 과정

  1. 생성: 스프링이 스프링 빈 대상이 되는 객체를 생성

  2. 전달: 빈 후처리기에 생성된 객체를 전달

  3. 모든 Advisor 빈 조회: 자동 프록시 생성기가 스프링 컨테이너에서 모든 Advisor을 조회

  4. 프록시 적용 대상 체크: Advisor내에 있는 Pointcut을 이용해 모든 클래스와 메서드를 하나하나 매칭해본다. 이때 조건이 하나라도 만족하면 프록시 적용 대상이 된다.

  5. 프록시 생성: 프록시 적용 대상이면 프록시를 생성하고 반환해서 프록시를 스프링 빈으로 등록한다.




🎈 주의

  • 프록시를 모든 곳에 생성하는 것은 비용 낭비이다. 최소한의 프록시만 적용해야 한다.
  • 따라서 Pointcut을 잘 작성해 원하는 프록시만 만드는게 중요하다.
    • 포인트컷 표현식 작성에는 여러 방법이 있는데, 실무에서는 AspectJ를 주로 사용한다.
      • AspectJ은 다음에 더 자세히 알아보도록 하자.



📌 예시

  • Advisor을 빈으로 등록만 하면 스프링이 알아서 찾아서 빈 후처리기에 등록해준다.
@Configuration
public class AutoProxyConfig {
    @Bean
    public Advisor advisor(LogTrace logTrace) {
        //pointCut
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution(* hello.proxy.app..*(..)) && !execution(* hello.proxy.app..noLog(..))");

        //advice
        LogTraceAdvice advice = new LogTraceAdvice(logTrace);
        return new DefaultPointcutAdvisor(pointcut, advice);
    }
}
  • execution(* hello.proxy.app..*(..)) && !execution(* hello.proxy.app..noLog(..))
    • *: 모든 반환 타입
    • hello.proxy.app..: 해당 패키지와 그 하위 패키지
    • *(..): 모든 메서드(*), 파라미터는 상관 없음(..)
    • &&: 두 조건을 모두 만족
    • !: 반대
    • 자세한 포인트컷 문법은 여기 참고




📌 하나의 프록시, 여러 Advisor 적용

  • 스프링 컨테이너에 등록된 Advisor1Advisor2가 있다 가정하자.
  • 어떤 스프링 빈이 두 어드바이저의 적용 대상이라면??
    • 프록시 자동 생성기는 프록시를 하나만 생성한다.
    • 프록시 내부에는 여러 advisor을 포함할 수 있기 때문에 프록시를 여러 개 생성해서 낭비할 필요가 없다.

🎈 프록시 자동 생성기 상황별 정리

  • advisor1 의 포인트컷만 만족
    • 프록시1개 생성, 프록시에 advisor1 만 포함
  • advisor1, advisor2 의 포인트컷을 모두 만족
    • 프록시1개 생성, 프록시에 advisor1 , advisor2 모두 포함
  • advisor1 ,advisor2 의 포인트컷을 모두 만족하지 않음
    • 프록시가 생성되지 않음

인프런의 '스프링 핵심 원리 고급편(김영한)'을 스스로 정리한 글입니다.
자세한 내용은 해당 강의를 참고해주세요.

profile
I Think So!

0개의 댓글