前言
正常情况下,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加载顺序的资料请关注代码网其它相关文章!
发表评论