前言
正常情况下,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加载顺序的操作方法的详细内容,更多关于spring控制bean加载顺序的资料请关注代码网其它相关文章!
发表评论