Spring如何控制Bean的加载顺序
前言
正常情况下,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注解,缺点是类过多的时候需要一个个加注解,且不好维护。
@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 内部执行
ConfigurableApplicationContext#refresh()方法前;- 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);
});
}
}
执行结果如下

Spring如何控制Bean的加载顺序的更多相关文章
- 如果你还不知道如何控制springboot中bean的加载顺序,那你一定要看此篇
1.为什么需要控制加载顺序 springboot遵从约定大于配置的原则,极大程度的解决了配置繁琐的问题.在此基础上,又提供了spi机制,用spring.factories可以完成一个小组件的自动装配功 ...
- Spring Bean 的加载顺序
一,单一Bean 装载 1. 实例化; 2. 设置属性值; 3. 如果实现了BeanNameAware接口,调用setBeanName设置Bean的ID或者Name; 4. 如果实现BeanFacto ...
- spring源码-bean之加载-2
一.前面说了bean的容器初始化,后面当然是说bean的加载.这里还是不讲解ApplicationContext的bean的加载过程,还是通过最基础的XmlBeanFactory来进行讲解,主要是熟悉 ...
- Spring 容器中bean的加载过程
bean 的加载过程大致可以分为以下几个步骤: 1.获取配置的资源文件 2.对获取到的xml资源文件进行解析 3.获取包装资源 4.解析处理包装之后的资源 5.加载 提取bean 并进行注册(添加到b ...
- 为了控制Bean的加载我使出了这些杀手锏
故事一: 绝代有佳人,幽居在空谷 美女同学小张,在工作中遇到了烦心事.心情那是破凉破凉的,无法言喻. 故事背景是最近由于需求变动,小张在项目中加入了MQ的集成,刚开始还没什么问题,后面慢慢问题的显露出 ...
- SpringBoot系列教程之Bean加载顺序之错误使用姿势辟谣
在网上查询 Bean 的加载顺序时,看到了大量的文章中使用@Order注解的方式来控制 bean 的加载顺序,不知道写这些的博文的同学自己有没有实际的验证过,本文希望通过指出这些错误的使用姿势,让观文 ...
- 【spring】bean加载顺序
问题来源 有一个bean为A,一个bean为B.想要A在容器实例化的时候的一个属性name赋值为B的一个方法funB的返回值. 如果只是在A里单纯的写着: private B b; private S ...
- Spring Boot 配置加载顺序详解
使用 Spring Boot 会涉及到各种各样的配置,如开发.测试.线上就至少 3 套配置信息了.Spring Boot 可以轻松的帮助我们使用相同的代码就能使开发.测试.线上环境使用不同的配置. 在 ...
- spring源码学习之bean的加载(一)
对XML文件的解析基本上已经大致的走了一遍,虽然没有能吸收多少,但是脑子中总是有些印象的,接下来看下spring中的bean的加载,这个比xml解析复杂的多.这个加载,在我们使用的时候基本上是:Bea ...
- web.xml的配置及加载顺序
一web.xml加载过程(步骤): 1.启动WEB项目的时候,容器(如:Tomcat)会去读它的配置文件web.xml.读两个节点: <listener></listener> ...
随机推荐
- C++设计模式 - 门面模式(Facade)
接口隔离模式 在组件构建过程中,某些接口之间直接的依赖常常会带来很多问题.甚至根本无法实现.采用添加一层间接(稳定)接口,来隔离本来互相紧密关联的接口是一种常见的解决方案. 典型模式 Facade P ...
- [Unity] 为什么文件名和类名需要相同
挂载脚本时文件名和类名的关联方式 写过Unity脚本的人应该都知道,挂载脚本的文件名和类名必须相同 今天写新功能的时候偶然发现了这个规则的底层逻辑 并且发现这个规则并非必须的,实际上Unity是根据脚 ...
- 【直播回顾】战码先锋第五期:深入理解OpenHarmony系统启动,轻松踏上设备软件开发之旅
6月14日晚上19点,战"码"先锋第五期直播 <深入理解OpenHarmony系统启动,轻松踏上设备软件开发之旅> ,在OpenHarmony社群内成功举行. 本期 ...
- 基于 Java 编程生成二维码图片
0x01 准备 (1)软件版本 IntelliJ IDEA 2023.1.3 JDK 18 Tomcat 10.1.11 Maven 3.8.6 (2)技术栈 servlet zxing 谷歌项目 生 ...
- mysql 必知必会整理—数据插入和更新还有删除[十]
前言 简单整理数据插入更新还有删除. 正文 插入: INSERT INTO customers( customers.cust_address, customers.cust_city, custom ...
- c# ManualResetEventSlim
前言 后续会把异步编程的ManualResetEventSlim 深入写完,先简单介绍一下吧. ManualResetEventSlim 有set 方法和 reset .wait.dispose方法. ...
- MMDeploy部署实战系列【第三章】:MMdeploy pytorch模型转换onnx,tensorrt
MMDeploy部署实战系列[第三章]:MMdeploy pytorch模型转换onnx,tensorrt 这个系列是一个随笔,是我走过的一些路,有些地方可能不太完善.如果有那个地方没看懂,评论区问就 ...
- 使用pycuda替换字符串,使用cuda替换字符串
写一个python的cuda程序,实现字符串列表的字符串替换,把所有的123替换成xinyuuliu 以下是一个简单的 Python CUDA 代码示例,用于实现字符串列表的字符串替换.它使用了 NV ...
- 鸿蒙HarmonyO实战-ArkUI动画(组件内转场动画)
前言 转场动画是一种在电影.视频和演示文稿中使用的动画效果,用于平滑地切换不同的场景或幻灯片.转场动画可以增加视觉吸引力,改善观众的观看体验. 常见的转场动画包括淡入淡出.滑动.旋转.放大缩小等效果. ...
- 力扣184(MySQL)-部门工资最高的员工(中等)
题目: 表: Employee 表: Department 编写SQL查询以查找每个部门中薪资最高的员工.按 任意顺序 返回结果表.查询结果格式如下例所示. 解题思路: 方法一:窗口函数和多表联结 ...