Spring如何控制Bean的加载顺序

前言

正常情况下,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注解,缺点是类过多的时候需要一个个加注解,且不好维护

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

执行时机:

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

  2. SpringBoot 执行run()方法前。

一般有什么用呢?

在 SpringBoot 应用中 Classpath 上会有很多 jar 包,有些 jar 包需要在refresh()调用前对应用上下文做一些初始化动作,因此会提供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);
                });
    }
}

执行结果如下

文章转载自:fuxing.

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

体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构

相关推荐

  1. Spring如何控制Bean+执行顺序

    2024-05-11 11:14:05       23 阅读
  2. Spring@Bean通过配置文件实现控制???

    2024-05-11 11:14:05       50 阅读
  3. spring-boot控制bean创建顺序

    2024-05-11 11:14:05       35 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-05-11 11:14:05       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-05-11 11:14:05       100 阅读
  3. 在Django里面运行非项目文件

    2024-05-11 11:14:05       82 阅读
  4. Python语言-面向对象

    2024-05-11 11:14:05       91 阅读

热门阅读

  1. NLP经典入门论文

    2024-05-11 11:14:05       31 阅读
  2. 蓝桥杯备战4.双子数

    2024-05-11 11:14:05       26 阅读
  3. 程序员必须学会的道理,少走十年弯路!

    2024-05-11 11:14:05       29 阅读
  4. c#文心接口应用举例

    2024-05-11 11:14:05       35 阅读
  5. 从零开始学习MySQL 事务处理

    2024-05-11 11:14:05       25 阅读
  6. ubuntu 查看 postgresql 用户

    2024-05-11 11:14:05       32 阅读
  7. 商品购物车数据以店铺id为key,组合对应的数据

    2024-05-11 11:14:05       34 阅读
  8. 1、搭建TS开发环境(利用rollup)

    2024-05-11 11:14:05       37 阅读
  9. python dict赋值时有逗号自动变成元组

    2024-05-11 11:14:05       33 阅读
  10. 每天一个数据分析题(三百一十九)-图表

    2024-05-11 11:14:05       28 阅读
  11. 【前端每日一题】 day3

    2024-05-11 11:14:05       41 阅读