BeanFacotry的後置處理器詳解

2024年2月6日 17点热度 0人点赞

Spring 版本: 6.0.6

BeanFactory 的後置處理器的作用

BeanFactory 的後置處理器(PostProcessor)是用於在 BeanFactory 加載和創建 bean 過程中對 bean 進行進一步處理的接口。它提供了一種機制,可以在 Spring 容器實例化 bean 之前對 bean 進行定制、修改或擴展

兩種 BeanFactory 的接口類型

BeanFactoryPostProcessor

可以通過
ConfigurableListableBeanFactory 對 BeanDefinition 進行修改,這樣就會改變 bean 的定義

@FunctionalInterface
public interface BeanFactoryPostProcessor {
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

BeanDefinitionRegistryPostProcessor


BeanDefinitionRegistryPostProcessor 繼承了 BeanFactoryPostProcessor 接口,同時增加了一個接口,該接口提供了 BeanDefinitionRegistry 參數,也就是可以動態註入一些 BeanDefinition, 在 Spring 中典型的應用是
ConfigurationClassPostProcessor,後面會分析這個類

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}

BeanFactory 後置處理器的使用示例

使用示例類說明

  1. CusBeanFactoryPostProcessor 該類實現了 BeanFactoryPostProcessor 接口並且標有 @Component 註解
  2. CusBeanDefinitionRegistryPostProcessor 該類實現了 BeanDefinitionRegistryPostProcessor 接口並且標有 @Component 註解
  3. RegisterComponent 普通類,會通過 CusBeanDefinitionRegistryPostProcessor 註入到 Spring 容器
  4. ScanComponent 標有 @Component 和 @Scope("prototype"), 會通過 CusBeanFactoryPostProcessor 將 scope 從 prototype 改為 singleton
  5. BeanFactoryPostProcessMain 主類,標有 @Configuration 和 @ComponentScan

上述所有類都放在同一個包中

//  普通類,並沒有增加spring註解,會通過 CusBeanDefinitionRegistryPostProcessor 註入到 Spring 容器
public class RegisterComponent {
    public void sayHello() {
        System.out.println("RegisterComponent.sayHello");
    }
}
// 實現了BeanDefinitionRegistryPostProcessor接口,會被spring掃描,並且註入了普通類 RegisterComponent
@Component
public class CusBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(RegisterComponent.class).getBeanDefinition();
        registry.registerBeanDefinition("registerComponent", beanDefinition);
        System.out.println("CusBeanDefinitionRegistryPostProcessor postProcessBeanDefinitionRegistry");
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("CusBeanDefinitionRegistryPostProcessor postProcessBeanFactory");
    }
}
//  被spring管理的類,如果沒有任何處理會是 prototype 作用域, 這裡會通過 CusBeanFactoryPostProcessor 將 scope 改為 singleton
@Component
@Scope("prototype")
public class ScanComponent {
    public void sayHello() {
        System.out.println("BeanFactoryDemo1 sayHello");
    }
}
// 實現了BeanFactoryPostProcessor接口,會將scanComponent類的scope從prototype改為singleton
@Component
public class CusBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition scanComponent = beanFactory.getBeanDefinition("scanComponent");
        scanComponent.setScope("singleton");
        System.out.println("CusBeanFactoryPostProcessor postProcessBeanFactory");
    }
}
// 配置主類
@Configuration
@ComponentScan
public class BeanFactoryPostProcessMain {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(BeanFactoryPostProcessMain.class);
        // BeanFactoryPostProcessor 的測試(修改了 ScanComponent 類的 scope 屬性)
        ScanComponent bean = context.getBean(ScanComponent.class);
        System.out.println(bean);
        ScanComponent bean2 = context.getBean(ScanComponent.class);
        System.out.println(bean2);
        RegisterComponent registerComponent = context.getBean(RegisterComponent.class);
        registerComponent.sayHello(); // 會打印 "RegisterComponent.sayHello"
    }
}

執行結果

CusBeanDefinitionRegistryPostProcessor postProcessBeanDefinitionRegistry
CusBeanDefinitionRegistryPostProcessor postProcessBeanFactory
CusBeanFactoryPostProcessor postProcessBeanFactory
org.example.beanfactorypost.ScanComponent@5e1fa5b1
org.example.beanfactorypost.ScanComponent@5e1fa5b1
RegisterComponent.sayHello

從上面執行結果可以得出如下幾個結論:

  1. 先執行實現了 BeanDefinitionRegistryPostProcessor 接口的類,然後才是執行的 BeanFactoryPostProcessor 接口實現類
  2. BeanDefinitionRegistryPostProcessor 實現類確實可以註冊普通對象成為 bean, 比如上面註冊了普通對象 RegisterComponent
  3. CusBeanFactoryPostProcessor 類已經將 ScanComponent 的 scope 屬性改成 singleton, 因為兩次 getBean 獲取的是同一個對象

BeanFactory 後置處理器的執行時機

參考 [[Spring上下文refresh方法解析]] 中寫到的 refresh() 方法的第五步,就是執行後置處理器

執行流程如下

AnnotationConfigApplicationContextAbstractApplicationContextPostProcessorRegistrationDelegatenew AnnotationConfigApplicationContext(classes)refresh()invokeBeanFactoryPostProcessors()invokeBeanFactoryPostProcessors()AnnotationConfigApplicationContextAbstractApplicationContextPostProcessorRegistrationDelegate

所以最終是執行到 public
PostProcessorRegistrationDelegate#
invokeBeanFactoryPostProcessors() 方法 , 代碼這裡就不貼了,這裡總結一下

  1. 執行實現了 BeanDefinitionRegistryPostProcessors 和 PriorityOrdered 的類的postProcessBeanDefinitionRegistry() 方法
  2. 執行實現了 BeanDefinitionRegistryPostProcessors 和 Ordered 的類的postProcessBeanDefinitionRegistry() 方法
  3. 執行實現了 BeanDefinitionRegistryPostProcessors 並且在 前面兩步中沒有執行過的類
  4. 對於實現了 BeanFactoryPostProcessor 的類,調用流程也是類似,執行實現了 PriorityOrdered 的類 -> 執行實現了 Ordered 的類 -> 執行剩下的類

BeanDefinitionRegistryPostProcessor 典型實現類 ConfigurationClassPostProcessor

在 Spring 內部也是有很多實現了
BeanDefinitionRegistryPostProcessor 接口的類,比如
ConfigurationClassPostProcessor 類,下面就來看看這個類

  1. 先說明一下 ConfigurationClassPostProcessor 這個類做的事情,在 Spring 中 @ComponentScan 註解可以批量掃描類被 Spring 管理,但是註解隻是起到一個標記的作用,需要有地方來解析這個註解才行,而這個解析的源頭就是 ConfigurationClassPostProcessor,真正解析是在 ConfigurationClassParser 中
  2. 前面有說過 BeanDefinitionRegistryPostProcessors 接口的實現類可以批量註冊 BeanDefinition 被 Spring 管理,在 ConfigurationClassParser 中將 @ComponentScan 涉及到的類都解析出來之後,剛好就可以註冊到 Spring 容器中

代碼執行流程如下

AbstractApplicationContext#refresh
    AbstractApplicationContext#invokeBeanFactoryPostProcessors
        public PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
            private PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors
                ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
                    ConfigurationClassPostProcessor#processConfigBeanDefinitions
                        ConfigurationClassParser#parse
                            ComponentScanAnnotationParser#parse

上面是代碼的整體執行流程, 最終是通過
ComponentScanAnnotationParser 來進行解析 @ComponentScan 註解的

問題

上面代碼執行流程中,在
PostProcessorRegistrationDelegate#
invokeBeanDefinitionRegistryPostProcessors 中可以得到
ConfigurationClassPostProcessor 類,但是這個類我們並沒有手動進行註冊。


AbstractApplicationContext 中有
addBeanFactoryPostProcessor() 可以手動註冊

public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {
     @Override
	public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
		Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null");
		this.beanFactoryPostProcessors.add(postProcessor);
	}   
}

所以肯定是 Spring 在哪個步驟中自己註冊了,要想找到在哪裡註冊的也不難,那就是在
ConfigurationClassPostProcessor 類的
postProcessBeanDefinitionRegistry() 方法中打斷點,然後看調用棧,就可以知道
ConfigurationClassPostProcessor 對象是從哪裡獲取的,不同的上下文設置的方式可能不同,在給出結論之前再看一下我們的主類測試代碼

@Configuration
@ComponentScan
public class BeanFactoryPostProcessMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanFactoryPostProcessMain.class);
        // BeanFactoryPostProcessor 的測試(修改了 ScanComponent 類的 scope 屬性)
        ScanComponent bean = context.getBean(ScanComponent.class);
        System.out.println(bean);
        ScanComponent bean2 = context.getBean(ScanComponent.class);
        System.out.println(bean2);
        RegisterComponent registerComponent = context.getBean(RegisterComponent.class);
        registerComponent.sayHello(); // 會打印 "RegisterComponent.sayHello"
    }
}

從測試代碼中看到上下文對象是
AnnotationConfigApplicationContext, 所以下面給出的結論也是基於這個上下文對象, 下面代碼執行流程使用序號進行標記

/ new AnnotationConfigApplicationContext(classes) 
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    this();  // 1
    register(componentClasses);
    refresh();
}
// AnnotationConfigApplicationContext 類
public AnnotationConfigApplicationContext() {
    StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
    this.reader = new AnnotatedBeanDefinitionReader(this); // 2
    createAnnotatedBeanDefReader.end();
    this.scanner = new ClassPathBeanDefinitionScanner(this);
}
// AnnotatedBeanDefinitionReader 類
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
    this(registry, getOrCreateEnvironment(registry)); // 3
}
// AnnotatedBeanDefinitionReader 類
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    Assert.notNull(environment, "Environment must not be null");
    this.registry = registry;
    this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
    AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); // 4
}
// AnnotationConfigUtils 類
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
    registerAnnotationConfigProcessors(registry, null); // 5
}
// AnnotationConfigUtils 類
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {
    // public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME = "org.springframework.context.annotation.internalConfigurationAnnotationProcessor";
    // 省略
    if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); // 6
    }
    // 省略
    return beanDefs;
}
// AnnotationConfigUtils 類
private static BeanDefinitionHolder registerPostProcessor(
			BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
    definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    registry.registerBeanDefinition(beanName, definition); // 7
    return new BeanDefinitionHolder(definition, beanName);
}
// GenericApplicationContext 類
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
        throws BeanDefinitionStoreException {
    this.beanFactory.registerBeanDefinition(beanName, beanDefinition); // 8
}
// DefaultListableBeanFactory 類
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {
    // 省略
    this.beanDefinitionNames.add(beanName); // 9 
    // 省略
}

至此已經知道
ConfigurationClassPostProcessor 是在何處添加的,而且
ConfigurationClassPostProcessor 類對應的 beanName 是
org.springframework.context.annotation.internalConfigurationAnnotationProcessor