经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring » 查看文章
Spring如何控制Bean的加载顺序
来源:cnblogs  作者:fuxing.  时间:2024/5/11 8:55:51  对本文有异议

前言

正常情况下,Spring 容器加载 Bean 的顺序是不确定的,那么我们如果需要按顺序加载 Bean 时应如何操作?本文将详细讲述我们如何才能控制 Bean 的加载顺序。




场景

我创建了 4 个 Class 文件,分别命名为

  1. FirstInitialization
  2. SecondInitialization
  3. ThirdInitialization
  4. ForthInitialization

我希望这 4 个类按照 1、2、3、4 的顺序加载。

如下图,直接加载的话,顺序是 1、4、2、3,并不能达到要求。

如何控制


注意:网上很多文章说Order注解或Ordered接口可以控制 Bean 的加载顺序,其是并不能,它们的作用是定义 Spring IOC 容器中 Bean 定义类的执行顺序的优先级,并不是定义加载顺序。


使用@DependsOn 注解

在需要调整顺序的类上依次加@DependsOn注解,缺点是类过多的时候需要一个个加注解,且不好维护

  1. @Component
  2. public class FirstInitialization {
  3. @PostConstruct
  4. public void init(){
  5. System.out.println("我是第一个加载!");
  6. }
  7. }
  1. @Component
  2. @DependsOn("firstInitialization")
  3. public class SecondInitialization {
  4. @PostConstruct
  5. public void init(){
  6. System.out.println("我是第二个加载!");
  7. }
  8. }
  1. @Component
  2. @DependsOn("secondInitialization")
  3. public class ThirdInitialization {
  4. @PostConstruct
  5. public void init(){
  6. System.out.println("我是第三个加载!");
  7. }
  8. }
  1. @Component
  2. @DependsOn("thirdInitialization")
  3. public class ForthInitialization {
  4. @PostConstruct
  5. public void init(){
  6. System.out.println("我是第四个加载!");
  7. }
  8. }

执行结果如下

基于 ApplicationContextInitializer 接口


接口简介

这里我简单介绍一个这个接口的用处, 等到整理到相关源码的时候再详细介绍。

ApplicationContextInitializer接口是在 Spring 容器刷新之前执行的一个回调函数。

执行时机:

  1. Spring 内部执行ConfigurableApplicationContext#refresh()方法前;
  2. SpringBoot 执行run()方法前。


一般有什么用呢?

在 SpringBoot 应用中 Classpath 上会有很多 jar 包,有些 jar 包需要在refresh()调用前对应用上下文做一些初始化动作,因此会提供ApplicationContextInitializer接口的实现类,放在如下图的文件中,这样会被SpringApplication#initialize发现,然后完成对应初始化。

实现步骤


首先创建一个类继承ApplicationContextInitializer接口。

  1. public class MyApplicationContextInitializer implements ApplicationContextInitializer {
  2. @Override
  3. public void initialize(ConfigurableApplicationContext applicationContext) {
  4. //将自定义的BeanFactoryPostProcessor实现类保存到ApplicationContext中
  5. applicationContext.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());
  6. }
  7. }

创建`META-INF/spring.factories`文件。


自定义`BeanDefinitionRegistryPostProcessor`。
  1. /**
  2. * BeanFactoryPostProcessor的子类
  3. * 允许开发人员在Bean定义注册之前和之后对BeanDefinition进行自定义处理,例如添加,修改或删除Bean定义等。
  4. */
  5. public class MyBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {
  6. // 初始化需要排序的类,这里要保证插入顺序只能用LinkedHashMap
  7. private static final Map<String, Class> ORDER_BEAN_MAP = new LinkedHashMap<>() {
  8. {
  9. put("firstInitialization", FirstInitialization.class);
  10. put("secondInitialization", SecondInitialization.class);
  11. put("thirdInitialization", ThirdInitialization.class);
  12. put("forthInitialization", ForthInitialization.class);
  13. }
  14. };
  15. @Override
  16. public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
  17. Optional.ofNullable(ORDER_BEAN_MAP.keySet()).orElse(new HashSet<>()).stream()
  18. .forEach(beanName -> {
  19. // 初始化一个 Bean 定义
  20. AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
  21. .genericBeanDefinition().getBeanDefinition();
  22. // 按顺序注册每个Bean
  23. beanDefinition.setBeanClass(ORDER_BEAN_MAP.get(beanName));
  24. registry.registerBeanDefinition(beanName, beanDefinition);
  25. });
  26. }
  27. }

执行结果如下

原文链接:https://www.cnblogs.com/fuxing/p/18181623

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号