前言

正常情况下,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);
});
}
}

执行结果如下

Spring如何控制Bean的加载顺序的更多相关文章

  1. 如果你还不知道如何控制springboot中bean的加载顺序,那你一定要看此篇

    1.为什么需要控制加载顺序 springboot遵从约定大于配置的原则,极大程度的解决了配置繁琐的问题.在此基础上,又提供了spi机制,用spring.factories可以完成一个小组件的自动装配功 ...

  2. Spring Bean 的加载顺序

    一,单一Bean 装载 1. 实例化; 2. 设置属性值; 3. 如果实现了BeanNameAware接口,调用setBeanName设置Bean的ID或者Name; 4. 如果实现BeanFacto ...

  3. spring源码-bean之加载-2

    一.前面说了bean的容器初始化,后面当然是说bean的加载.这里还是不讲解ApplicationContext的bean的加载过程,还是通过最基础的XmlBeanFactory来进行讲解,主要是熟悉 ...

  4. Spring 容器中bean的加载过程

    bean 的加载过程大致可以分为以下几个步骤: 1.获取配置的资源文件 2.对获取到的xml资源文件进行解析 3.获取包装资源 4.解析处理包装之后的资源 5.加载 提取bean 并进行注册(添加到b ...

  5. 为了控制Bean的加载我使出了这些杀手锏

    故事一: 绝代有佳人,幽居在空谷 美女同学小张,在工作中遇到了烦心事.心情那是破凉破凉的,无法言喻. 故事背景是最近由于需求变动,小张在项目中加入了MQ的集成,刚开始还没什么问题,后面慢慢问题的显露出 ...

  6. SpringBoot系列教程之Bean加载顺序之错误使用姿势辟谣

    在网上查询 Bean 的加载顺序时,看到了大量的文章中使用@Order注解的方式来控制 bean 的加载顺序,不知道写这些的博文的同学自己有没有实际的验证过,本文希望通过指出这些错误的使用姿势,让观文 ...

  7. 【spring】bean加载顺序

    问题来源 有一个bean为A,一个bean为B.想要A在容器实例化的时候的一个属性name赋值为B的一个方法funB的返回值. 如果只是在A里单纯的写着: private B b; private S ...

  8. Spring Boot 配置加载顺序详解

    使用 Spring Boot 会涉及到各种各样的配置,如开发.测试.线上就至少 3 套配置信息了.Spring Boot 可以轻松的帮助我们使用相同的代码就能使开发.测试.线上环境使用不同的配置. 在 ...

  9. spring源码学习之bean的加载(一)

    对XML文件的解析基本上已经大致的走了一遍,虽然没有能吸收多少,但是脑子中总是有些印象的,接下来看下spring中的bean的加载,这个比xml解析复杂的多.这个加载,在我们使用的时候基本上是:Bea ...

  10. web.xml的配置及加载顺序

    一web.xml加载过程(步骤): 1.启动WEB项目的时候,容器(如:Tomcat)会去读它的配置文件web.xml.读两个节点: <listener></listener> ...

随机推荐

  1. HTTP长连接和短链接代理与网关

    长连接和短链接 代理与网关 HTTP/)服务器端网关:网关与客户端使用HTTP协议通信,使用其他协议与服务端通信 (/HTTP)客户端网关:网关与客户端使用其他协议通信,使用HTTP协议与服务端通信 ...

  2. 动态数组(Array)

    Array 存储具有一对一逻辑关系数据的存储顺序结构. 数组最大的优点:快速查询,最好应用于索引有语义的情况. 插入元素 template<typename T> bool Array&l ...

  3. #分治NTT#CF1218E Product Tuples

    Codeforces 用 OGF 表示 \(F(B,x)\) 就是 \[\prod_{i=1}^n(1+(q-a_i)x) \] 直接分治 NTT 把 \([x^k]\) 也就是这一位的系数求出来就可 ...

  4. #左偏树,树形dp#洛谷 1552 [APIO2012]派遣

    题目 分析 那我指定管理层之后,选择薪水越小的人越好, 考虑小根堆,由于需要合并,所以采用左偏树 代码 #include <cstdio> #include <cctype> ...

  5. #Tarjan,SPFA,差分约束系统#BZOJ 2330 AcWing 368 银河

    题目 分析 首先这明显是一道差分约束题,但是无解的情况确实比较恶心, 考虑它的边权为0或1,无解当且仅当某个强连通分量内的边至少一条边边权为1, 那么用有向图的Tarjan缩点后跑SPFA就可以了 代 ...

  6. OpenHarmony Meetup 广州站 OpenHarmony正当时—技术开源

      招募令 OpenHarmony Meetup 广州站 火热招募中,等待激情四射的开发者,线下参与OpenHarmonyMeetup线下交流 展示前沿技术.探讨未来可能.让你了解更多专属OpenHa ...

  7. 【直播回顾】OpenHarmony知识赋能六期第三课—OpenHarmony智能家居项目之控制面板功能实现

    7月14日晚上19点,知识赋能第六期第三节直播 <OpenHarmony智能家居项目之控制面板功能实现> ,在OpenHarmony开发者成长计划社群内成功举行. 本次直播是"O ...

  8. Pyside2简单案例

    代码: from PySide2.QtWidgets import QApplication, QMainWindow, QPushButton, QPlainTextEdit app = QAppl ...

  9. HarmonyOS语言基础类库开发指南上线啦!

      语言基础类库提供哪些功能?多线程并发如何实现?TaskPool(任务池)和Worker在实现和使用场景上有何不同? 针对开发者关注的并发等语言基础类库的相关能力,我们在新推出的语言基础类库开发指南 ...

  10. k8s集群安装(kubeadm方式)

    一.准备三台虚拟机,系统CentOS7.9: 192.168.1.221 master1 192.168.1.189  node1 192.168.1.60  node2 二..对三台虚拟机初始化 1 ...