SpringBoot控制配置类加载顺序方式

 更新时间:2023年05月26日 14:44:35   作者:zengjyxxz  
这篇文章主要介绍了SpringBoot控制配置类加载顺序方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

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之间的依赖先后顺序。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Spring 重定向(Redirect)指南及相关策略问题

    Spring 重定向(Redirect)指南及相关策略问题

    本文介绍了在Spring中实现重定向的三种不同方法,在执行这些重定向时如何处理/传递属性以及如何处理HTTP POST请求的重定向。关于Spring 重定向(Redirect)指南的相关知识大家参考下本文
    2017-11-11
  • Java 通过反射变更String的值过程详解

    Java 通过反射变更String的值过程详解

    这篇文章主要介绍了Java 通过反射变更String的值过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-10-10
  • mybatis plus时间判断问题

    mybatis plus时间判断问题

    在MyBatisPlus中,时间判断可以通过XML转义的方式实现,例如使用>、<、<>、>=、<=进行比较,这种方法涉及到SQL符号的转义,确保查询语句的安全性和准确性,特别是在处理大于、小于和等于等逻辑时,正确的转义能够防止SQL注入等安全问题
    2024-09-09
  • Java Record基本用法详解

    Java Record基本用法详解

    Java Record通过极简语法和不可变性,显著减少了数据类的样板代码,同时提升了代码安全性和可维护性,其适用于 DTO、模式匹配、函数式编程等场景,感兴趣的朋友一起看看吧
    2025-07-07
  • Java数据结构之线索化二叉树的实现

    Java数据结构之线索化二叉树的实现

    在二叉树的结点上加上线索的二叉树称为线索二叉树,对二叉树以某种遍历方式进行遍历,使其变为线索二叉树的过程称为对二叉树进行线索化。本文将详解如何实现线索化二叉树,需要的可以参考一下
    2022-05-05
  • 使用Maven打包、发布、配置版本号命令

    使用Maven打包、发布、配置版本号命令

    在软件开发过程中,打包和发布是关键步骤,本文介绍了如何在打包和发布时跳过测试,如何指定项目版本号,以及如何指定配置文件,提供了实用的技巧和方法,希望对开发者有所帮助
    2024-09-09
  • SpringBoot集成ip2region实现ip白名单的代码示例

    SpringBoot集成ip2region实现ip白名单的代码示例

    ip2region v2.0 - 是一个离线IP地址定位库和IP定位数据管理框架,10微秒级别的查询效率,提供了众多主流编程语言的 xdb 数据生成和查询客户端实现,本文介绍了SpringBoot集成ip2region实现ip白名单的代码工程,需要的朋友可以参考下
    2024-08-08
  • Java两个乒乓球队比赛名单问题(判断素数)

    Java两个乒乓球队比赛名单问题(判断素数)

    两个乒乓球队进行比赛,各出三人。甲队为a,b,c三人,乙队为x,y,z三人。已抽签决定比赛名单。有人向队员打听比赛的名单。a说他不和x比,c说他不和x,z比,请编程序找出三队赛手的名单
    2017-02-02
  • java正则表达式对特殊字符的转义以及异常现象

    java正则表达式对特殊字符的转义以及异常现象

    这篇文章主要给大家介绍了关于java正则表达式对特殊字符的转义以及异常现象的相关资料,在Java中使用正则表达式匹配特殊字符也需要使用转义字符"\",需要的朋友可以参考下
    2023-06-06
  • Java使用5个线程计算数组之和

    Java使用5个线程计算数组之和

    本文主要介绍了Java使用5个线程计算数组之和,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05

最新评论