SpringBoot控制配置类加载顺序方式
作者:zengjyxxz 发布时间:2022-08-18 04:31:15
SpringBoot控制配置类加载顺序
@Configuration配置被加载进容器的方式大体上可分为3种
手动:构建ApplicationContext时由构建者手动传入,可手动控制顺序。
自动1:被@ComponentScan自动扫描进去,无法控制顺序。
自动2:自动扫描,运用SpringBoot的3大注解,可以控制顺序。
控制配置类加载顺序
2.1、传统的 Spring Framework 控制配置类加载顺序
在传统的 Spring Framework 里,一个 @Configuration 注解标注的类就代表一个配置类,当存在多个 @Configuration 时,他们的执行顺序是由使用者靠手动指定的,就像这样:
// 手动控制Config1 Config2的顺序
ApplicationContext context = new AnnotationConfigApplicationContext(Config1.class, Config2.class);
2.2、SpringBoot 控制配置类加载顺序
第一步:把 A_SonConfig 和 B_ParentConfig 挪动到 Application 扫描不到的包内,切记:一定且必须是扫描不到的包内(可以放到启动类扫描不到的目录)。
第二步:当前工程里增加配置META-INF/spring.factories,内容为(配置里Son和Parent前后顺序对结果无影响):
org.springframework.boot.autoconfigure.EnableAutoConfiguration=x.A_SonConfig,x.B_ParentConfig
第三步:通过 SpringBoot 自动配置顺序相关的三大注解 @AutoConfigureBefore、@AutoConfigureAfter、@AutoConfigureOrder作用于自动配置类。
@AutoConfigureBefore(A_SonConfig.class)
@Configuration
public class B_ParentConfig {
? ? B_ParentConfig() {
? ? ? ? System.out.println("配置类ParentConfig构造器被执行...");
? ? }
}
注意:
SpringBoot 自动配置三大注解不能作用于被启动类扫描的配置类中。
Spring Boot的自动配置均是通过spring.factories来指定的,它的优先级最低(执行时机是最晚的);通过扫描进来的优先级是最高的。
Spring Boot的自动配置是通过@EnableAutoConfiguration注解驱动的,默认是开启状态。你也可以通过spring.boot.enableautoconfiguration = false来关闭它,回退到Spring Framework时代。
如何正确控制springboot中bean的加载顺序
为什么需要控制加载顺序
springboot遵从约定大于配置的原则,极大程度的解决了配置繁琐的问题。在此基础上,又提供了spi机制,用spring.factories可以完成一个小组件的自动装配功能。
在一般业务场景,可能你不大关心一个bean是如何被注册进spring容器的。只需要把需要注册进容器的bean声明为@Component即可,spring会自动扫描到这个Bean完成初始化并加载到spring上下文容器。
而当你在项目启动时需要提前做一个业务的初始化工作时,或者你正在开发某个中间件需要完成自动装配时。你会声明自己的Configuration类,但是可能你面对的是好几个有互相依赖的Bean。如果不加以控制,这时候可能会报找不到依赖的错误。
但是你明明已经把相关的Bean都注册进spring上下文了呀。这时候你需要通过一些手段来控制springboot中的bean加载顺序。
几个误区
在正式说如何控制加载顺序之前,先说2个误区。
在标注了@Configuration的类中,写在前面的@Bean一定会被先注册
这个不存在的,spring在以前xml的时代,也不存在写在前面一定会被先加载的逻辑。因为xml不是渐进的加载,而是全部parse好,再进行依赖分析和注册。到了springboot中,只是省去了xml被parse成spring内部对象的这一过程,但是加载方式并没有大的改变。
利用@Order这个标注能进行加载顺序的控制
严格的说,不是所有的Bean都可以通过@Order这个标注进行顺序的控制。你把@Order这个标注加在普通的方法上或者类上一点鸟用都没有。
那@Order能控制哪些bean的加载顺序呢,我们先看看官方的解释:
最开始@Order注解用于切面的优先级指定;在 4.0 之后对它的功能进行了增强,支持集合的注入时,指定集合中 bean 的顺序,并且特别指出了,它对于当 实例的 bean 之间的顺序,没有任何影响。
目前用的比较多的有以下3点:
控制AOP的类的加载顺序,也就是被@Aspect标注的类
控制ApplicationListener实现类的加载顺序
控制CommandLineRunner实现类的加载顺序
如何控制
1.@DependsOn
@DependsOn注解可以用来控制bean的创建顺序,该注解用于声明当前bean依赖于另外一个bean。所依赖的bean会被容器确保在当前bean实例化之前被实例化。
示例:
以上代码bean的加载顺序为:
@DependsOn的使用:
直接或者间接标注在带有@Component注解的类上面;
直接或者间接标注在带有@Bean注解的方法上面;
使用@DependsOn注解到类层面仅仅在使用 component-scanning 方式时才有效,如果带有@DependsOn注解的类通过XML方式使用,该注解会被忽略,<bean depends-on="..."/>这种方式会生效。
2.参数注入
在@Bean标注的方法上,如果你传入了参数,springboot会自动会为这个参数在spring上下文里寻找这个类型的引用。并先初始化这个类的实例。
利用此特性,我们也可以控制bean的加载顺序。
示例:
以上结果,beanB先于beanA被初始化加载。
需要注意的是,springboot会按类型去寻找。如果这个类型有多个实例被注册到spring上下文,那你就需要加上@Qualifier("Bean的名称")来指定
3.利用bean的生命周期中的扩展点
在spring体系中,从容器到Bean实例化&初始化都是有生命周期的,并且提供了很多的扩展点,允许你在这些步骤时进行逻辑的扩展。
这些可扩展点的加载顺序由spring自己控制,大多数是无法进行干预的。我们可以利用这一点,扩展spring的扩展点。在相应的扩展点加入自己的业务初始化代码。从来达到顺序的控制。
4.@AutoConfigureOrder
这个注解用来指定配置文件的加载顺序。但是在实际测试中发现,以下这样使用是不生效的:
无论你2个数字填多少,都不会改变其加载顺序结果。
那这个@AutoConfigureOrder到底是如何使用的呢。
经过测试发现,@AutoConfigureOrder只能改变外部依赖的@Configuration的顺序。如何理解是外部依赖呢。
能被你工程内部scan到的包,都是内部的Configuration,而spring引入外部的Configuration,都是通过spring特有的spi文件:spring.factories
换句话说,@AutoConfigureOrder能改变spring.factories中的@Configuration的顺序。
具体使用方式:
spring.factories:
心得:
其实在工作中,我相信很多人碰到过复杂的依赖关系的bean加载,把这种不确定 * 给spring去做,还不如我们自己去控制,这样在阅读代码的时候 ,也能轻易看出bean之间的依赖先后顺序。
来源:https://blog.csdn.net/zengjyxxz/article/details/106709457


猜你喜欢
- 1.面对对象的初步认识1.1什么是面向对象用面向对象的思想来涉及程序,更符合人们对事物的认知,对于大型程序的设计、扩展以及维护都非常友好。1
- 随着Android设备增多,不少网站都开始设备Android设备,而Android主流设备类型以手机和平板为主。网站在适配时通过User A
- Android手机震动抖动效果的实现(1)布局文件如下<RelativeLayout xmlns:android="http
- 1.什么是灰度发布?灰度发布又称金丝雀发布,是在系统升级的时候能够平滑过渡的一种发布方式。在其上可以进行A/B测试,即让一部分用户继续用产品
- Android中的Service和其调用者既可以在同一个App中,也可以在不同的App。如果Service在App1中,而调用Service
- RecyclerView是Android 5.0新增的控件,在android-support-v7下面。官方文档对RecycleView介绍
- 目录I. 项目环境1. 项目依赖II. 缓存注解介绍1. @Cacheable2. @CachePut3. @CacheEvict4. @C
- 1. ThreadLocal详解JDK1.2版本起,Java就提供了java.lang.ThreadLocal,ThreadLocal为每个
- 在很多系统开发中,我们希望在指定的方法调用之前或者之后能打印出该方法的调用时间以及方法的出参和入参,就可以使用spring的AOP,还可以结
- 发生服务器 500 异常,如果默认方式处理,则是将异常捕获之后跳到 Tomcat 缺省的异常页面,如下图所示。不论哪个网站都是一样的,所以为
- AntPathMatcher前言(1)SpringMVC的路径匹配规则是依照Ant的来的,实际上不只是SpringMVC,整个Spring框
- 最近有小伙伴告诉我,在循环的判断条件只会计算一次,本金鱼不相信,于是就做了测试,本文记录我做的测试。先来写一个简单的代码, 就一个循环,循环
- Purpose开发人员在合作的时候经常遇到以下场景:1.开发人员A在自己的本地数据库做了一些表结构的改动,并根据这些改动调整了DAO层的代码
- 目标:查询数据库中的字段,然后转换成 JSON 格式的数据,返回前台。环境:idea 2016.3.4, jdk 1.8, mysql 5.
- 目录环境依赖数据源方案一 使用 Spring Boot 默认配置方案二 手动创建脚本初始化使用 JdbcTemplate 操作实体对象DAO
- 目前系统集成短信似乎是必不可少的部分,由于各种云平台都提供了不同的短信通道,这里我们增加多租户多通道的短信验证码,并增加配置项,使系统可以支
- 反射方式获取JPA Entity属性和值在记录日志或者调试的时候,往往需要输出数据库查询或者写入的值,或者在接 * 互的时候,可能需要将实体转
- 实现的效果如下:我在ListView的Item长按事件内打开一个弹出窗口,窗口内有一个EditText对象,在这个编辑框内输入文本点确定后,
- 这个可以在Adapter里面写一般写完之后都会调用 public void removeItem(int pos){ &nbs
- @Value获取application.properties配置无效问题无效的原因主要是要注意@Value使用的注意事项:1、不能作用于静态