Spring怎样控制Bean的加载顺序

打印 上一主题 下一主题

主题 845|帖子 845|积分 2545

前言

正常情况下,Spring 容器加载 Bean 的顺序是不确定的,那么我们如果必要按顺序加载 Bean 时应怎样操纵?本文将详细报告我们怎样才气控制 Bean 的加载顺序。


场景

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

  • FirstInitialization
  • SecondInitialization
  • ThirdInitialization
  • 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 容器刷新之前执行的一个回调函数。


执行机遇:

  • Spring 内部执行ConfigurableApplicationContext#refresh()方法前;
  • 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. }
复制代码
执行结果如下


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

来自云龙湖轮廓分明的月亮

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表