SpringBoot-扩展点
参考文献
SpringBoot
扩展点
ApplicationContextInitializer
BeanDefinitionRegistryPostProcessor
BeanFactoryPostProcessor
InstantiationAwareBeanPostProcessor
SmartInstantiationAwareBeanPostProcessor
BeanFactoryAware
ApplicationContextAwareProcessor
BeanNameAware
InitializingBean
FactoryBean
SmartInitializingSingleton
CommandLineRunner
DisposableBean
ApplicationListener
ApplicationContextInitializer
1 | package org.springframework.context; |
触发时机
ApplicationContextInitializer
接口的实现类的执行时机是在Spring
容器正式刷新前,准备上下文环境时.
1 | org.springframework.boot.SpringApplication#run(java.lang.String...) |
1 | protected void applyInitializers(ConfigurableApplicationContext context) { |
使用步骤
-
实现
ApplicationContextInitializer
接口1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17package cn.holelin.spring.extend;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import java.util.Map;
public class TestApplicationContextInitializer implements ApplicationContextInitializer {
public void initialize(ConfigurableApplicationContext applicationContext) {
Map<String, Object> systemProperties = applicationContext.getEnvironment().getSystemProperties();
System.out.println("---------------start------------------");
systemProperties.forEach((key,value)->{
System.out.println("key:"+key+",value:"+value);
}); System.out.println("---------------end------------------");
}
} -
把实现类注册到
Spring
容器中-
方法一: 调用
org.springframework.boot.SpringApplication#addInitializers
方法将实现的类添加到容器中1
2
3
4
5
6
7
8
9
10
11
12
13
import cn.holelin.spring.extend.TestApplicationContextInitializer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
public class Application {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(Application.class);
springApplication.addInitializers(new TestApplicationContextInitializer());
springApplication.run(args);
}
} -
方法二: 通过在项目的
resources
目录下创建META-INF/spring.factories
,将实现类配置到该文件中1
org.springframework.context.ApplicationContextInitializer=cn.holelin.spring.extend.TestApplicationContextInitializer
-
原理:
1
2
3
4
5
6
7
8
9
10
11
12public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
// 关键点,构造函数中会去META-INF/spring.factories下配置的所有initializers添加到容器中
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
-
-
方法三: 通过在
application.yaml
配置文件中配置1
2
3context:
initializer:
classes: cn.holelin.spring.extend.TestApplicationContextInitializer- 原理: 方法二中
META-INF/spring.factories
中org.springframework.boot.context.config.DelegatingApplicationContextInitializer
类用于处理context.initializer.classes
配置
- 原理: 方法二中
-
BeanDefinitionRegistryPostProcessor
-
作用:
BeanDefinitionRegistryPostProcessor
是BeanFactoryPostProcessor
的一个子接口,它提供了更早期的回调时机,使你可以在bean定义注册时干预Spring IoC
容器的初始化流程,甚至可以动态注册、修改或移除BeanDefinition
. -
使用场景: 当你需要在容器初始化阶段注册新的
bean
定义,或者修改和删除已经注册的bean
定义时,应该使用BeanDefinitionRegistryPostProcessor
.例如,动态注册一些依赖于外部条件的bean
或者从注册中心中删除某些bean
.
BeanFactoryPostProcessor vs BeanDefinitionRegistryPostProcessor
BeanFactoryPostProcessor
: 主要用于在所有的BeanDefinition
都被加载到BeanFactory
后,修改已存在的BeanDefinition
.不能在BeanFactoryPostProcessor
中动态注册新的BeanDefinition
BeanDefinitionRegistryPostProcessor
: 不仅能够修改BeanDefinition
,还允许动态注册和删除BeanDefinition
.它的回调时机比BeanFactoryPostProcessor
早,允许对BeanDefinitionRegistry
进行直接操作.
触发时机
1 | org.springframework.context.support.AbstractApplicationContext#refresh |
- 在
PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()
方法中,并不是直接就初始化和执行postProcessBeanDefinitionRegistry()
和postProcessBeanFactory()
,而是又进行了一系列的判断,其判断顺序是:- 通过
AbstractApplicationContext#addBeanFactoryPostProcessor
提前注册的BeanDefinitionRegistryPostProcessor
实现类; - 实现了
PriorityOrdered
接口; - 是否实现了
Ordered
; - 剩下的其他
BeanDefinitionRegistryPostProcessor
实现类
- 通过
1 | /** |
使用步骤
- 实现
BeanDefinitionRegistryPostProcessor
接口,在postProcessBeanDefinitionRegistry
中实现具体逻辑
BeanFactoryPostProcessor
触发时机
- 调用时机在
Spring
在读取beanDefinition
信息之后,实例化bean
之前
1 | org.springframework.context.support.AbstractApplicationContext#refresh |
InstantiationAwareBeanPostProcessor
BeanPostProcess
接口只在bean
的初始化阶段进行扩展(注入Spring上下文前后),而InstantiationAwareBeanPostProcessor
接口在此基础上增加了3个方法,把可扩展的范围增加了实例化阶段和属性注入阶段.- 该类主要的扩展点有以下5个方法,主要在bean生命周期的两大阶段: 实例化阶段和初始化阶段:
postProcessBeforeInstantiation
: 实例化bean
之前,相当于new
这个bean
之前postProcessAfterInstantiation
: 实例化bean
之后,相当于new
这个bean
之后postProcessPropertyValues
:bean
已经实例化完成,在属性注入时阶段触发,@Autowired
,@Resource
等注解原理基于此方法实现postProcessBeforeInitialization
: 初始化bean
之前,相当于把bean
注入Spring
上下文之前postProcessAfterInitialization
: 初始化bean
之后,相当于把bean
注入Spring
上下文之后
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 HoleLin's Blog!