Spring擴充套件介面(3):BeanFactoryPostProcessor

2023-10-19 21:02:18

在此係列文章中,我總結了Spring幾乎所有的擴充套件介面,以及各個擴充套件點的使用場景。並整理出一個bean在spring中從被載入到最終初始化的所有可延伸點的順序呼叫圖。這樣,我們也可以看到bean是如何一步步載入到spring容器中的。


BeanFactoryPostProcessor

1、概述

public interface BeanFactoryPostProcessor {
    void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;
}

BeanFactoryPostProcessor是Spring框架中的一個重要介面,用於在BeanFactory載入Bean定義之後、範例化Bean之前對BeanFactory進行自定義修改和擴充套件。它允許開發人員在Spring容器載入組態檔並建立Bean範例之前對Bean定義進行操作,例如修改屬性值、新增額外的後設資料等。

在應用程式啟動時,Spring容器會自動檢測並呼叫所有實現了BeanFactoryPostProcessor介面的類的postProcessBeanFactory方法。開發人員可以利用這個方法來實現自定義的邏輯,從而實現一些高階的自定義邏輯和功能擴充套件。

前文介紹的BeanDefinitionRegistryPostProcessor為其子介面。

2、簡單案例

下面是一個範例,展示瞭如何實現動態的給Bean修改屬性值:

public class User {
    String name;
    String password;
}

import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("user");
        if (Objects.nonNull(beanDefinition)) {
            MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
            propertyValues.addPropertyValue("name", "張三");
            propertyValues.addPropertyValue("password", "123456");
        }
    }
}

同樣,若當容器中有多個BeanFactoryPostProcessor的時候,可以通過實現PriorityOrdered或Ordered介面來指定順序(優先執行PriorityOrdered的介面,其次是Ordered的介面,最後是沒有實現任何排序的介面):

@Override
public int getOrder() {
   return 0; //值越小,優先順序越高
}

3、原始碼分析

  • 在MyBeanFactoryPostProcessor打上斷點,啟動SpringApplication,可以看到左下角的呼叫鏈路。

  • spring的AbstractApplicationContext的refresh方法,執行this.invokeBeanFactoryPostProcessors(beanFactory)。

  • 接下來進入核心的invokeBeanFactoryPostProcessors方法,大概邏輯是先取出所有實現了BeanFactoryPostProcessor介面的類,在for迴圈中根據實現類的優先順序放入不同的ArrayList()等待呼叫,先PriorityOrdered,再Ordered,最後呼叫無優先順序的實現類。
  • 注意:BeanDefinitionRegistryPostProcessor也實現了BeanFactoryPostProcessor介面,所以postProcessorNames也包含BeanDefinitionRegistryPostProcessor實現類,它已先於BeanFactoryPostProcessor執行,所以在for迴圈中需要排除,見if (!processedBeans.contains(ppName))。

  • 最後,遍歷呼叫BeanFactoryPostProcessor的元件