BeanPostProcessor 是在何時介入 Bean 建立的?

張哥說技術發表於2023-10-23

來源:江南一點雨

今天來和各位小夥伴詳細分析一下 BeanPostProcessor。今天這篇是原理分析,基本用法松哥之前已經講過了,有影片也有文章,對影片感興趣的小夥伴戳這裡:Spring原始碼應該怎麼學?。

不同於前面和大家分享的 BeanFactoryPostProcessor,BeanPostProcessor 從名字上就能看出來,這是一個 Bean 的後置處理器,也就是說,BeanPostProcessor 其實主要是對已經建立出來的 Bean 做一些後置處理,而 BeanFactoryPostProcessor 主要是針對 BeanDefinition 做後置處理(此時 Bean 物件還沒建立出來)。

但是,BeanPostProcessor 家族裡邊也有例外,即 MergedBeanDefinitionPostProcessor,這是一個 BeanPostProcessor,但是卻可以處理 BeanDefinition。

這一切都是咋回事呢?我們今天就來分析分析。

1. BeanPostProcessor

首先我們先來看一下 BeanPostProcessor 介面的定義:

public interface BeanPostProcessor {

 @Nullable
 default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  return bean;
 }

 @Nullable
 default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  return bean;
 }

}

這裡就是兩個方法,理解這兩個方法有一個大的前提,就是此時 Spring 容器已經透過 Java 反射建立出來 Bean 物件了,只不過在初始化這個 Bean 物件的時候,又提供了一些配置介面:

  • postProcessBeforeInitialization:這個是在 Bean 初始化之前觸發,此時我們已經有一個 Bean 物件了,但是 Bean 中一些生命週期方法如 InitializingBean 介面的 afterPropertiesSet 方法、自定義的 init-method 方法等都尚未執行,在這些方法執行之前觸發 postProcessBeforeInitialization 方法。
  • postProcessAfterInitialization:類似於上面,在 afterPropertiesSet 和自定義的 init-method 之後觸發該方法。

BeanPostProcessor 的應用非常廣泛,在整個 Spring 體系中,也扮演了非常重要的角色,如 @Bean 註解的解析、AOP 動態代理的生成等等許多我們日常使用的功能,都是透過 BeanPostProcessor 來實現的。

2. MergedBeanDefinitionPostProcessor

MergedBeanDefinitionPostProcessor 算是整個 BeanPostProcessor 家族中比較另類的一個介面了,它雖然是 BeanPostProcessor,但是卻可以處理 BeanDefinition。MergedBeanDefinitionPostProcessor 介入的時機就是 Bean 建立成功之後,Bean 中各個屬性填充之前。

MergedBeanDefinitionPostProcessor 用於在 Bean 定義合併之後對合並後的 Bean 進行後置處理。它的作用是允許開發者在 Bean 定義合併完成後,對合並後的 Bean 進行自定義的修改或擴充套件操作。通常情況下,這個介面用於處理帶有註解的 Bean 定義,例如 @Autowired 或 @Value 等註解的處理。透過實現 MergedBeanDefinitionPostProcessor 介面,開發者可以在 Bean 定義合併後,對這些註解進行解析和處理,以實現自定義的邏輯。

來看下 MergedBeanDefinitionPostProcessor 介面:

public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {

 void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);

 default void resetBeanDefinition(String beanName) {
 }

}

這裡就兩個方法,一個是處理合併後的 BeanDefinition,還有一個是重置 Bean 的。

3. 收集 BeanPostProcessor

接下來我們來看 BeanPostProcessor 的處理流程,首先第一步就是在容器啟動的時候,收集到使用者註冊在系統中的 BeanPostProcessor,無論是 Java 配置還是 XML 配置,在 refresh 方法中都會呼叫到 registerBeanPostProcessors,這個方法就是用來收集 BeanPostProcessor 的。

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
 PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
public static void registerBeanPostProcessors(
  ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext)
 
{
 String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.classtruefalse);
 int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
 beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
 List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
 List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
 List<String> orderedPostProcessorNames = new ArrayList<>();
 List<String> nonOrderedPostProcessorNames = new ArrayList<>();
 for (String ppName : postProcessorNames) {
  if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
   BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
   priorityOrderedPostProcessors.add(pp);
   if (pp instanceof MergedBeanDefinitionPostProcessor) {
    internalPostProcessors.add(pp);
   }
  }
  else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
   orderedPostProcessorNames.add(ppName);
  }
  else {
   nonOrderedPostProcessorNames.add(ppName);
  }
 }
 sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
 registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
 List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
 for (String ppName : orderedPostProcessorNames) {
  BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
  orderedPostProcessors.add(pp);
  if (pp instanceof MergedBeanDefinitionPostProcessor) {
   internalPostProcessors.add(pp);
  }
 }
 sortPostProcessors(orderedPostProcessors, beanFactory);
 registerBeanPostProcessors(beanFactory, orderedPostProcessors);
 List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
 for (String ppName : nonOrderedPostProcessorNames) {
  BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
  nonOrderedPostProcessors.add(pp);
  if (pp instanceof MergedBeanDefinitionPostProcessor) {
   internalPostProcessors.add(pp);
  }
 }
 registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
 sortPostProcessors(internalPostProcessors, beanFactory);
 registerBeanPostProcessors(beanFactory, internalPostProcessors);
 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}

這裡的程式碼我就不逐行解釋了,我來說一下整體的處理思路。

這裡用來儲存 BeanPostProcessor 的集合一共有四個,分別是:

  • priorityOrderedPostProcessors:由於 BeanPostProcessor 可能存在多個,所以我們需要給這多個 BeanPostProcessor 進行排序,排序的方式有兩種,一種就是在定義 BeanPostProcessor 的時候,讓其實現 PriorityOrdered 介面,那麼這裡就是把所有實現了 PriorityOrdered 介面的 BeanPostProcessor 收集到一起。
  • orderedPostProcessors:類似於上面的,這裡是收集所有實現了 Ordered 介面的 BeanPostProcessor。
  • nonOrderedPostProcessors:這個裡邊儲存了所有不需要排序的 BeanPostProcessor。
  • internalPostProcessors:這個裡邊儲存了 MergedBeanDefinitionPostProcessor 型別的 BeanPostProcessor,前三種互相之間不會重複,而 internalPostProcessors 可能會和前三種有重複。

將收集並且排序好的 BeanPostProcessor,呼叫 registerBeanPostProcessors 方法進行註冊:

private static void registerBeanPostProcessors(
  ConfigurableListableBeanFactory beanFactory, List<? extends BeanPostProcessor> postProcessors)
 
{
 if (beanFactory instanceof AbstractBeanFactory abstractBeanFactory) {
  // Bulk addition is more efficient against our CopyOnWriteArrayList there
  abstractBeanFactory.addBeanPostProcessors(postProcessors);
 }
 else {
  for (BeanPostProcessor postProcessor : postProcessors) {
   beanFactory.addBeanPostProcessor(postProcessor);
  }
 }
}

這裡最終就是把收集到的 BeanPostProcessor 新增到容器的 beanPostProcessors 變數中。

現在,容器中已經有了 BeanPostProcessor 了,接下來看什麼時候執行。

4. 觸發 BeanPostProcessor

BeanPostProcessor 的執行分為兩種情況,一種是執行 MergedBeanDefinitionPostProcessor 型別的 BeanPostProcessor,還有一種是執行普通的 BeanPostProcessor,我們分別來看。

在建立 Bean 的關鍵方法 AbstractAutowireCapableBeanFactory#doCreateBean 中,有這樣幾個關鍵步驟:

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
  throws BeanCreationException 
{
    // 初始化 Bean 例項
 BeanWrapper instanceWrapper = null;
 if (mbd.isSingleton()) {
  instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
 }
 if (instanceWrapper == null) {
  instanceWrapper = createBeanInstance(beanName, mbd, args);
 }
 Object bean = instanceWrapper.getWrappedInstance();
 Class<?> beanType = instanceWrapper.getWrappedClass();
 if (beanType != NullBean.class{
  mbd.resolvedTargetType = beanType;
 }
 // Allow post-processors to modify the merged bean definition.
 synchronized (mbd.postProcessingLock) {
  if (!mbd.postProcessed) {
   try {
    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
   }
   catch (Throwable ex) {
    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
      "Post-processing of merged bean definition failed", ex);
   }
   mbd.markAsPostProcessed();
  }
 }
    //省略
 try {
  populateBean(beanName, mbd, instanceWrapper);
  exposedObject = initializeBean(beanName, exposedObject, mbd);
 }
    //省略
 return exposedObject;
}

大家看到,在初始化 Bean 例項之後,有一個 applyMergedBeanDefinitionPostProcessors 方法,這個方法就是用來觸發 MergedBeanDefinitionPostProcessor 執行的。

populateBean 方法是給 Bean 的各個屬性填充值的,填充完成之後,呼叫 initializeBean 方法進行剩餘的初始化工作,在 initializeBean 方法中,呼叫了其餘的 BeanPostProcessor。

4.1 觸發 MergedBeanDefinitionPostProcessor

protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
 for (MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) {
  processor.postProcessMergedBeanDefinition(mbd, beanType, beanName);
 }
}

4.2 觸發其他 BeanPostProcessor

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
 invokeAwareMethods(beanName, bean);
 Object wrappedBean = bean;
 if (mbd == null || !mbd.isSynthetic()) {
  wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
 }
 try {
  invokeInitMethods(beanName, wrappedBean, mbd);
 }
 catch (Throwable ex) {
  throw new BeanCreationException(
    (mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);
 }
 if (mbd == null || !mbd.isSynthetic()) {
  wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
 }
 return wrappedBean;
}

大家看這個順序,先是調 applyBeanPostProcessorsBeforeInitialization,這個裡邊最終就觸發到了 BeanPostProcessor#postProcessBeforeInitialization 方法;然後呼叫 invokeInitMethods,afterPropertiesSet 和自定義的 init-method 都在這裡被觸發;最後呼叫 applyBeanPostProcessorsAfterInitialization,這個裡邊最終就觸發到 BeanPostProcessor#postProcessAfterInitialization 方法。

好啦,這就是和小夥伴們梳理的 BeanPostProcessor 原理了,感興趣的小夥伴可以自己 DEBUG 跑一遍哦~

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024923/viewspace-2990425/,如需轉載,請註明出處,否則將追究法律責任。

相關文章