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 後置處理器的使用示例
使用示例類說明
- CusBeanFactoryPostProcessor 該類實現了 BeanFactoryPostProcessor 接口並且標有 @Component 註解
- CusBeanDefinitionRegistryPostProcessor 該類實現了 BeanDefinitionRegistryPostProcessor 接口並且標有 @Component 註解
- RegisterComponent 普通類,會通過 CusBeanDefinitionRegistryPostProcessor 註入到 Spring 容器
- ScanComponent 標有 @Component 和 @Scope("prototype"), 會通過 CusBeanFactoryPostProcessor 將 scope 從 prototype 改為 singleton
- 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
從上面執行結果可以得出如下幾個結論:
- 先執行實現了 BeanDefinitionRegistryPostProcessor 接口的類,然後才是執行的 BeanFactoryPostProcessor 接口實現類
- BeanDefinitionRegistryPostProcessor 實現類確實可以註冊普通對象成為 bean, 比如上面註冊了普通對象 RegisterComponent
- CusBeanFactoryPostProcessor 類已經將 ScanComponent 的 scope 屬性改成 singleton, 因為兩次 getBean 獲取的是同一個對象
BeanFactory 後置處理器的執行時機
參考 [[Spring上下文refresh方法解析]] 中寫到的 refresh() 方法的第五步,就是執行後置處理器
執行流程如下
AnnotationConfigApplicationContextAbstractApplicationContextPostProcessorRegistrationDelegatenew AnnotationConfigApplicationContext(classes)refresh()invokeBeanFactoryPostProcessors()invokeBeanFactoryPostProcessors()AnnotationConfigApplicationContextAbstractApplicationContextPostProcessorRegistrationDelegate
所以最終是執行到 public
PostProcessorRegistrationDelegate#
invokeBeanFactoryPostProcessors() 方法 , 代碼這裡就不貼了,這裡總結一下
- 執行實現了 BeanDefinitionRegistryPostProcessors 和 PriorityOrdered 的類的postProcessBeanDefinitionRegistry() 方法
- 執行實現了 BeanDefinitionRegistryPostProcessors 和 Ordered 的類的postProcessBeanDefinitionRegistry() 方法
- 執行實現了 BeanDefinitionRegistryPostProcessors 並且在 前面兩步中沒有執行過的類
- 對於實現了 BeanFactoryPostProcessor 的類,調用流程也是類似,執行實現了 PriorityOrdered 的類 -> 執行實現了 Ordered 的類 -> 執行剩下的類
BeanDefinitionRegistryPostProcessor 典型實現類 ConfigurationClassPostProcessor
在 Spring 內部也是有很多實現了
BeanDefinitionRegistryPostProcessor 接口的類,比如
ConfigurationClassPostProcessor 類,下面就來看看這個類
- 先說明一下 ConfigurationClassPostProcessor 這個類做的事情,在 Spring 中 @ComponentScan 註解可以批量掃描類被 Spring 管理,但是註解隻是起到一個標記的作用,需要有地方來解析這個註解才行,而這個解析的源頭就是 ConfigurationClassPostProcessor,真正解析是在 ConfigurationClassParser 中
- 前面有說過 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