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++移动构造与std::move()
背景及问题 如下程序所示: #include<iostream> class MyString { public: MyString() = default; MyString(const ...
- 第一个hello驱动
Linux驱动程序的分类 字符设备驱动.块设备驱动和网络设备驱动. Linux驱动程序运行方式 把驱动程序编译进内核里面,这样内核启动后就会自动运行驱动程序了: 把驱动程序编译成以.ko为后缀的模块文 ...
- #dp#C 公共子序列
题目 给定两个字符串\(s1,s2\),求它们的\(LCS\) 满足\(|s1|\leq 10^6,|s2|\leq 10^3\) 分析 考场写了\(O(|s1|*|s2|)\)成功TLE, 考虑突破 ...
- OpenHarmony 官网文档有哪些上新?上篇:应用开发文档上新
随着 OpenAtom OpenHarmony(以下简称"OpenHarmony")系统能力持续升级,已具备支撑复杂带屏标准设备和应用开发的基础能力.相较于旧版本,OpenHarm ...
- SQline安装
SQLite 安装 SQLite 的一个重要的特性是零配置的,这意味着不需要复杂的安装或管理.本章将讲解 Windows.Linux 和 Mac OS X 上的安装设置. 在 Windows 上安装 ...
- Health Kit申请验证有问题?解决方案全解析
在接入Health Kit的过程中,应用上线前需要完成申请验证环节,获得正式的运动健康权限. 我们贴心整理了申请验证被驳回的高频问题,您可以在申请前阅读以下内容,避免在您的申请材料中出现下述问题影响审 ...
- Qt使用https协议发送带参数的post请求
背景: 现在公司项目需要做一个检测更新的功能,通过访问后台接口,判断是否需要更新. 后台接口是 https 协议的,接口需要post请求,需要带参数,来判断是哪个软件需要做检测更新的操作. 客户端软件 ...
- 重新点亮shell————awk 控制语句[十三]
前言 简单介绍一下控制语句. 正文 例子1: 例子2: 例子3 for循环: 例子4, sum会复用: 同样,其他的while 和 do while 也是可以在awk中使用的. 结 下一节awk数组.
- c# 反编译对比(旧)
前言 旧的都是我以前博客的迁移. 我们写代码有时候遇到一些问题,或者我们想优化我们的代码,我们想要看编译后的运行情况,那么反编译是必须要做的一件事. 正文 在此我自己使用的是reflector和ILS ...
- mysql 重新整理——索引优化一个简单的案例 [十一]
前言 经过了前面的一系列理论,那么用一个例子去看一下吧. 正文 EXPLAIN SELECT t3.emp_no,t3.first_name,(select t4.last_name from tem ...