BeanPostProcessor

appti·2024년 3월 13일
0

분석

목록 보기
8/25

정의

새롭게 생성된 빈 인스턴스를 변경할 수 있는 일종의 팩토리 훅입니다.

ApplicationContext는 refresh 과정 중에 BeanPostProcessor를 등록하며, 이렇게 등록된 BeanPostProcessor는 빈 인스턴스를 생성할 때 이를 자동으로 감지해 적용할 수 있습니다.

대표적인 예시는 마커 인터페이스를 확인하거나, 빈을 프록시로 래핑하는 것입니다.

메서드

다음과 같이 두 개의 메서드가 존재합니다.

postProcessBeforeInitialization()

빈의 속성이 세팅된 이후, 빈의 초기화 메서드가 실행되기 전에 호출됩니다.

대표적인 사례는 빈을 프록시로 래핑할 때입니다.

postProcessAfterInitialization()

빈의 초기화 메서드가 실행된 이후에 호출됩니다

대표적인 사례는 마커 인터페이스를 확인할 때입니다.

빈의 초기화 메서드

@PostConstruct이나 @Bean의 initMethod, InitializingBean 등으로 명시한 메서드를 의미합니다.

다만 시점이 빈의 초기화 메서드 실행 전/후로 나뉠 뿐이지, 빈의 초기화 메서드가 없어도 호출됩니다.

빈의 초기화 메서드를 지정하지 않은 일반적인 스프링 빈 또한 BeanFactory에 의해 BeanPostProcessor를 호출하고 있음을 확인할 수 있습니다.

Ordered, PriorityOrdered

다른 BeanPostProcessor에 의존적인 BeanPostProcessor가 있을 수 있습니다.

이런 BeanPostProcessor는 Ordered 혹은 PriorityOrdered를 구현해 동작 순서를 지정할 수 있습니다.

주의할 점으로는 @Order로는 순서를 지정할 수 없다는 것입니다.

PriorityOrdered를 구현한 AutowiredAnnotationBeanPostProcessor가 order를 관리하고 있는 것을 확인할 수 있습니다.

동작 시점

BeanPostProcessor는 Bean 인스턴스 생성 전/후로 동작하게 됩니다.

BeanFactory의 라이프 사이클에서도 동작 시점 확인이 가능합니다.


스프링 부트 3.0.8 버전, Spring MVC 기반에서 BeanFactory의 일종인 AbstractAutowireCapableBeanFactory에서 빈을 생성하는 시점에 호출됩니다.

init-method를 실행하는 invokeInitMethods() 호출 전에 postProcessBeforeInitialization()를 호출하고 있음을 확인할 수 있습니다.

refresh에서 사용하는 BeanPostProcessor

실행 환경은 스프링 부트 3.0.8, 애노테이션 기반, JPA 및 actuator, 모니터링(프로메테우스)를 의존하고 있는 상황입니다.

Application refresh에서 사용하는 BeanPostProcessor는 다음과 같습니다.

  • ApplicationContextAwareProcessor
    • ApplicationContextAware, Aware 인터페이스를 구현한 빈들에 대해 해당 ApplicationContext에 접근성을 제공합니다.
  • WebApplicationContextServletContextAwareProcessor
    • ServletContextAware 인터페이스를 구현한 빈에 ServletContext를 주입합니다.
  • ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor
    • @Configuration 클래스에서 @Import로 가져온 설정들을 처리합니다.
  • PostProcessorRegistrationDelegate$BeanPostProcessorChecker
    • BeanPostProcessor가 올바르게 등록되었는지 검사합니다.
  • ConfigurationPropertiesBindingPostProcessor
    • @ConfigurationProperties 애노테이션이 붙은 빈의 프로퍼티를 바인딩합니다.
  • AnnotationAwareAspectJAutoProxyCreator
    • @AspectJ 애노테이션 기반의 AOP 프록시를 자동으로 생성합니다.
  • FilteredMethodValidationPostProcessor
    • 메소드 수준에서의 Bean 검증을 활성화합니다.
  • PersistenceExceptionTranslationPostProcessor
    • JPA 예외를 Spring의 데이터 접근 예외 계층으로 변환합니다.
  • WebServerFactoryCustomizerBeanPostProcessor
    • Embedded WebServer의 설정을 처리합니다.
  • ErrorPageRegistrarBeanPostProcessor
    • ErrorController와 연동되는 에러 페이지를 등록합니다.
  • HealthEndpointConfiguration$HealthEndpointGroupsBeanPostProcessor
    • 애플리케이션 헬스 체크를 위한 엔드포인트 그룹을 구성합니다.
  • MeterRegistryPostProcessor
    • micrometer의 메트릭 레지스트리를 구성합니다.
  • MetricsRepositoryMethodInvocationListenerBeanPostProcessor
    • MetricsRepositoryMethodInvocationListener를 등록해 Spring Data Repository의 메트릭을 수집합니다.
  • ObservationRegistryPostProcessor
    • 지연 초기화된 ObservationRegistryConfigurer에 작업을 위임해 ObservationRegistry 빈을 후처리합니다.
  • ProjectingArgumentResolverRegistrar$ProjectingArgumentResolverBeanPostProcessor
    • 메소드 파라미터의 프로젝션을 처리합니다.
  • PersistenceAnnotationBeanPostProcessor
    • JPA 관련 애노테이션을 처리합니다.
  • CommonAnnotationBeanPostProcessor
    • JSR-250 애노테이션(@Resource, @PostConstruct, @PreDestroy 등)을 처리합니다.
  • AutowiredAnnotationBeanPostProcessor
    • @Autowired, @Value, @Inject 등의 애노테이션을 처리합니다.
  • InitDestroyAnnotationBeanPostProcessor
    • @PostConstruct 및 @PreDestroy 애노테이션을 처리합니다.
  • ScheduledAnnotationBeanPostProcessor
    • @Scheduled 애노테이션을 통해 정의된 스케줄링 작업을 처리합니다.
  • ApplicationListenerDetector
    • EventListener를 감지하고 빈으로 등록합니다.

AnnotationAwareAspectJAutoProxyCreator 동작 과정

AnnotationAwareAspectJAutoProxyCreator는 @AspectJ 애노테이션 기반의 AOP 프록시를 자동으로 생성합니다.

AOP 프록시를 자동으로 생성하고 빈으로 등록하기 때문에 postProcessBeforeInitialization()가 동작할 것이라고 추측할 수 있습니다.

AnnotationAwareAspectJAutoProxyCreator의 계층 구조는 위와 같으며, 실제로는 AbstractAutoProxyCreator.postProcessBeforeInitialization()가 호출됩니다.

동작 과정은 다음과 같습니다.

  • ApplicationContext refresh 과정 중 registerBeanPostProcessors()에서 BeanPostProcessor가 등록됩니다.
    • 이 때, AnnotationAwareAspectJAutoProxyCreator는 등록되면서 이전에 빈으로 등록된 모든 Advisor를 조회합니다.
  • AbstractAutowireCapableBeanFactory가 빈 인스턴스를 생성합니다.
  • 빈 인스턴스의 초기화 메서드가 호출된 이후, AnnotationAwareAspectJAutoProxyCreator가 트리거됩니다.

이후 동작 과정은 코드를 보며 확인하겠습니다.

BeanPostProcessor에서 null을 반환한다면 위와 같이 기존 빈을 반환하게 됩니다.

해당 메서드에서 사용하는 필드의 의미는 다음과 같습니다.

  • advisedBeans : 이미 프록시를 생성하였거나 생성할 필요가 없는 빈들을 관리하기 위해 사용
  • targetSourcedBeans : 개발자가 직접 프로그래밍 방식으로 AOP 대상 객체를 정의한 경우 식별자를 관리하기 위해 사용
  • proxyTypes : 생성한 프록시의 타입을 캐싱하기 위해 사용

빈의 이름과 타입을 통해 cacheKey를 생성합니다.

빈 이름이 비어 있거나, targetSourcedBeans에 포함되어 있지 않다면 해당 분기문에 들어갑니다.

이미 프록시로 등록했거나 등록해서는 안 되는 빈이라면 null을 반환합니다.

빈의 타입이 인프라와 관련이 되어 있거나, 빈 이름이 AutowireCapableBeanFactory 규칙에 따라 빈 타입과 일치하는 경우라면 프록시로 변환해 빈으로 등록하면 안되므로 advisedBeans에 추가한 뒤 null을 반환합니다.

빈 이름과 빈 클래스 타입으로부터 TargetSource를 조회합니다.
이 과정을 통해 해당 빈이 프록시로 등록해야 하는 여부를 파악합니다.

TargetSource, 프록시로 등록해야 하는 빈의 경우 해당 분기문이 동작합니다.

이 시점까지 도달했다면 빈의 이름은 반드시 존재하므로, 항상 동작한다고 볼 수 있습니다.
TargetSource가 존재하므로 빈 이름(= 식별자)를 targetSourcedBeans에 저장합니다.

프록시를 생성하기 위해 Advice, Advisor를 조회하고 프록시를 생성합니다.

프록시를 생성했으므로 이를 proxyTypes에 캐싱하고 반환합니다.

TargetSource가 없다면 프록시로 생성할 빈이 아니므로 null을 반환합니다.

profile
안녕하세요

0개의 댓글