当前栏目
谈谈Spring boot 启动层面的开发
Spring boot的启动可以主要分为2个阶段。1 是调用AbstractApplicationContext的refresh方法之前和调用AbstractApplicationContext的refresh。 我们知道AbstractApplicationContext的refresh的方法是一个模板方法。几乎所有类型的ApplicationContext的初始化都是围绕这个refresh方法来进行。
1. refresh方法之前
1.1 ApplicationContextInitializer
这个类Spring boot***进行调用的类,其主要就是初始化一些BeanFactoryPostProcessor(后面会说明),或者一些在Application 初始化的时候就需要做的事情。而这些类通过通过扫描calsspath路径下的:META-INF/spring.factories 文件中的org.springframework.context.ApplicationContextInitializer字来加载类的全路径名,通过反射获取对象,然后调用initialize方法。
1.2 ApplicationListener
这个和ApplicationContextInitializer加载的方式类似,也是从META-INF/spring.factories文件中的配置,主要作用就是在Spring boot的初始化不同阶段会处罚不同的事件(ApplicationEvent及其子类),而这些监听器就会根据自己在不同事件触发的情况下完成自己的处理逻辑。例如,ConfigFileApplicationListener负责加载配置文件。
当然也可以通过其他方式加入beanFactory中,详情可以参照BeanFactoryPostProcessor加入到beanFactory的方法
1.ApplicationListener的有些事件是在ApplicationContextInitializer之前触发的
2.建议不要直接在ApplicationContextInitializer加入自己的BeanFactoryPostProcessor方法,xxxAware是不会帮你注入的。
2. refresh方法
这个就是spring的模板方法,主要有3个比较重要的接口
2.1 BeanFactoryPostProcessor
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
这个方法就是给可以对beanFactory进行一些自定义的操作,例如加入一些bean等。当然前提就是我们定义的bean是在beanFactory中。有许多办法可以做到
- 在ApplicationContextInitializer中定义加入,例如
public class MyContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());
}
}
- 通过其他BeanFactoryPostProcessor加入,可以通过注解@Import或者加载XML)
例如通过@Import(value={AnnotationBeanDefinitionRegistrar.class})
@Configuration
public class AnnotationBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
private String BEAN_NAME = "annotationBeanPostProcessor";
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
List<String> basePackages = getPackagesToScan(importingClassMetadata);
if (!registry.containsBeanDefinition(BEAN_NAME)) {
addPostProcessor(registry, basePackages);
}
}
private void addPostProcessor(BeanDefinitionRegistry registry, List<String> basePackages) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(AnnotationBeanPostProcessor.class);
beanDefinition.getConstructorArgumentValues()
.addGenericArgumentValue(basePackages);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN_NAME, beanDefinition);
}
private List<String> getPackagesToScan(AnnotationMetadata metadata) {
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
metadata.getAnnotationAttributes(EnableDubbo.class.getName()));
String[] basePackages = attributes.getStringArray("basePackages");
return Arrays.asList(basePackages);
}
}
这样,就可以加入我们自定义的BeanFactoryPostProcessor,就可以在Bean注册的层面上进行开发
2.2 BeanPostProcessor
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
这个接口主要就是针对在bean实例化前后做一些定制开发。一般只针对某个接口或者某个注解进行批量操作
3. 综述
1. 如果你需要在SpringApplication初始化的时候就做一些事情,使用ApplicationContextInitializer
2. 如果你需要SpringApplication的某个特定阶段做一些事情,使用ApplicationListener(推荐)
3. 如果你需要在beanFactory层面上开发,使用BeanFactoryPostProcessor(推荐)
4. 如果你需要在对某个bean的实例化层面上开发,使用BeanPostProcessor(一般业务上的开发使用InitializingBean或者init-method能够满足)
转载请注明出处:https://my.oschina.net/u/3039671/blog/852211
例子,Spring boot风格使用dubbo
码云:https://git.oschina.net/null_584_3382/spring-dubbo-parent
相关文章
- 鲜为人知但很有用的 HTML 属性
- 翻转再翻转!有意思的水平横向溢出滚动
- 自定义计数器小技巧!CSS 实现长按点赞累加动画
- 过五关!React高频面试题指南
- 软件开发中的十个认知偏差
- 不需要 JS!仅用 CSS 也能达到监听页面滚动的效果!
- 一文读懂TypeScript类型兼容性
- Vue 的响应式原则与双向数据绑定
- 快速掌握 TypeScript 新语法:Infer Extends
- JWT教你如何证明你是我的人!
- 一篇带给你 V8 GC 的实现
- 面试官:请使用JS完成一个LRU缓存?
- 通过可视化来学习JavaScript事件循环
- 新的跨域策略:使用 COOP、COEP 为浏览器创建更安全的环境
- 为什么有人说 vite 快,有人却说 vite 慢?
- 种草 Vue3 中几个好玩的插件和配置
- 超全面的前端工程化配置指南
- Vue 状态管理未来样子
- Volatile关键字能保证原子性么?
- 面试突击:SpringBoot 有几种读取配置文件的方法?