目录
- 前言
- 场景
- 如何控制
- 使用@DependsOn 注解
- 基于 ApplicationContextInitializer 接口
前言
- 正常情况下,Spring 容器加载 Bean 的顺序是不确定的,那么我们如果需要按顺序加载 Bean 时应如何操作?本文将详细讲述我们如何才能控制 Bean 的加载顺序。
复制代码 场景
我创建了 4 个 Class 文件,分别命名为
- FirstInitialization
- SecondInitialization
- ThirdInitialization
- ForthInitialization
我希望这 4 个类按照 1、2、3、4 的顺序加载。
如下图,直接加载的话,顺序是 1、4、2、3,并不能达到要求。
如何控制
- <strong>注意</strong>:网上很多文章说[code]Order
复制代码注解或 接口可以控制 Bean 的加载顺序,其是并不能,它们的作用是定义 Spring IOC 容器中 Bean 定义类的执行顺序的优先级,并不是定义加载顺序。[/code]
使用@DependsOn 注解
在需要调整顺序的类上依次加 注解,缺点是类 过多的时候需要一个个加注解,且不好维护。 - @Component
- public class FirstInitialization {
- @PostConstruct
- public void init(){
- System.out.println("我是第一个加载!");
- }
- }
复制代码- @Component
- @DependsOn("firstInitialization")
- public class SecondInitialization {
- @PostConstruct
- public void init(){
- System.out.println("我是第二个加载!");
- }
- }
复制代码- @Component
- @DependsOn("secondInitialization")
- public class ThirdInitialization {
- @PostConstruct
- public void init(){
- System.out.println("我是第三个加载!");
- }
- }
复制代码- @Component
- @DependsOn("thirdInitialization")
- public class ForthInitialization {
- @PostConstruct
- public void init(){
- System.out.println("我是第四个加载!");
- }
- }
复制代码执行结果如下
基于 ApplicationContextInitializer 接口
接口简介
这里我简单介绍一个这个接口的用处, 等到整理到相关源码的时候再详细介绍。 - ApplicationContextInitializer
复制代码接口是在 Spring 容器刷新之前执行的一个回调函数。 - 执行时机:
- Spring 内部执行[code]ConfigurableApplicationContext#refresh()
复制代码方法前;SpringBoot 执行 方法前。[/code]一般有什么用呢?
在 SpringBoot 应用中 Classpath 上会有很多 jar 包,有些 jar 包需要在 调用前对应用上下文做一些初始化动作,因此会提供 - ApplicationContextInitializer
复制代码接口的实现类,放在如下图的文件中,这样会被 - SpringApplication#initialize
复制代码发现,然后完成对应初始化。
实现步骤
首先创建一个类继承 - ApplicationContextInitializer
复制代码接口。 - public class MyApplicationContextInitializer implements ApplicationContextInitializer {
- @Override
- public void initialize(ConfigurableApplicationContext applicationContext) {
- //将自定义的BeanFactoryPostProcessor实现类保存到ApplicationContext中
- applicationContext.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());
- }
- }
复制代码创建 - META-INF/spring.factories
复制代码文件。
自定义 - BeanDefinitionRegistryPostProcessor
复制代码。 - /**
- * BeanFactoryPostProcessor的子类
- * 允许开发人员在Bean定义注册之前和之后对BeanDefinition进行自定义处理,例如添加,修改或删除Bean定义等。
- */
- public class MyBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {
- // 初始化需要排序的类,这里要保证插入顺序只能用LinkedHashMap
- private static final Map<String, Class> ORDER_BEAN_MAP = new LinkedHashMap<>() {
- {
- put("firstInitialization", FirstInitialization.class);
- put("secondInitialization", SecondInitialization.class);
- put("thirdInitialization", ThirdInitialization.class);
- put("forthInitialization", ForthInitialization.class);
- }
- };
- @Override
- public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
- Optional.ofNullable(ORDER_BEAN_MAP.keySet()).orElse(new HashSet<>()).stream()
- .forEach(beanName -> {
- // 初始化一个 Bean 定义
- AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
- .genericBeanDefinition().getBeanDefinition();
- // 按顺序注册每个Bean
- beanDefinition.setBeanClass(ORDER_BEAN_MAP.get(beanName));
- registry.registerBeanDefinition(beanName, beanDefinition);
- });
- }
- }
复制代码执行结果如下
以上就是Spring控制Bean加载顺序的操作方法的详细内容,更多关于Spring控制Bean加载顺序的资料请关注晓枫资讯其它相关文章!
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |