1.为什么需要控制加载顺序

springboot遵从约定大于配置的原则,极大程度的解决了配置繁琐的问题。在此基础上,又提供了spi机制,用spring.factories可以完成一个小组件的自动装配功能。

在一般业务场景,可能你不大关心一个bean是如何被注册进spring容器的。只需要把需要注册进容器的bean声明为@Component即可,spring会自动扫描到这个Bean完成初始化并加载到spring上下文容器。

而当你在项目启动时需要提前做一个业务的初始化工作时,或者你正在开发某个中间件需要完成自动装配时。你会声明自己的Configuration类,但是可能你面对的是好几个有互相依赖的Bean。如果不加以控制,这时候可能会报找不到依赖的错误。

但是你明明已经把相关的Bean都注册进spring上下文了呀。这时候你需要通过一些手段来控制springboot中的bean加载顺序。

2.几个误区

在正式说如何控制加载顺序之前,先说2个误区。

在标注了@Configuration的类中,写在前面的@Bean一定会被先注册

这个不存在的,spring在以前xml的时代,也不存在写在前面一定会被先加载的逻辑。因为xml不是渐进的加载,而是全部parse好,再进行依赖分析和注册。到了springboot中,只是省去了xml被parse成spring内部对象的这一过程,但是加载方式并没有大的改变。

利用@Order这个标注能进行加载顺序的控制

严格的说,不是所有的Bean都可以通过@Order这个标注进行顺序的控制。你把@Order这个标注加在普通的方法上或者类上一点鸟用都没有。

@Order能控制哪些bean的加载顺序呢,我们先看看官方的解释:

{@code @Order} defines the sort order for an annotated component. Since Spring 4.0, annotation-based ordering is supported for many kinds of components in Spring, even for collection injection where the order values of the target components are taken into account (either from their target class or from their {@code @Bean} method). While such order values may influence priorities at injection points, please be aware that they do not influence singleton startup order which is an orthogonal concern determined by dependency relationships and {@code @DependsOn} declarations (influencing a runtime-determined dependency graph).

最开始@Order注解用于切面的优先级指定;在 4.0 之后对它的功能进行了增强,支持集合的注入时,指定集合中 bean 的顺序,并且特别指出了,它对于但实例的 bean 之间的顺序,没有任何影响。

目前用的比较多的有以下3点:

  • 控制AOP的类的加载顺序,也就是被@Aspect标注的类

  • 控制ApplicationListener实现类的加载顺序

  • 控制CommandLineRunner实现类的加载顺序

3.如何控制

3.1@DependsOn

@DependsOn注解可以用来控制bean的创建顺序,该注解用于声明当前bean依赖于另外一个bean。所依赖的bean会被容器确保在当前bean实例化之前被实例化。

示例:

@Configuration
public class BeanOrderConfiguration {@Bean@DependsOn("beanB")public BeanA beanA(){System.out.println("bean A init");return new BeanA();}@Beanpublic BeanB beanB(){System.out.println("bean B init");return new BeanB();}@Bean@DependsOn({"beanD","beanE"})public BeanC beanC(){System.out.println("bean C init");return new BeanC();}@Bean@DependsOn("beanE")public BeanD beanD(){System.out.println("bean D init");return new BeanD();}@Beanpublic BeanE beanE(){System.out.println("bean E init");return new BeanE();}
}

以上代码bean的加载顺序为:

bean B init
bean A init
bean E init
bean D init
bean C init

@DependsOn的使用:

  • 直接或者间接标注在带有@Component注解的类上面;

  • 直接或者间接标注在带有@Bean注解的方法上面;

  • 使用@DependsOn注解到类层面仅仅在使用 component-scanning 方式时才有效,如果带有@DependsOn注解的类通过XML方式使用,该注解会被忽略,<bean depends-on="..."/>这种方式会生效。

3.2 参数注入

@Bean标注的方法上,如果你传入了参数,springboot会自动会为这个参数在spring上下文里寻找这个类型的引用。并先初始化这个类的实例。

利用此特性,我们也可以控制bean的加载顺序。

示例:

@Bean
public BeanA beanA(BeanB demoB){System.out.println("bean A init");return new BeanA();
}@Bean
public BeanB beanB(){System.out.println("bean B init");return new BeanB();
}

以上结果,beanB先于beanA被初始化加载。

需要注意的是,springboot会按类型去寻找。如果这个类型有多个实例被注册到spring上下文,那你就需要加上@Qualifier("Bean的名称")来指定

3.3 利用bean的生命周期中的扩展点

在spring体系中,从容器到Bean实例化&初始化都是有生命周期的,并且提供了很多的扩展点,允许你在这些步骤时进行逻辑的扩展。

这些可扩展点的加载顺序由spring自己控制,大多数是无法进行干预的。我们可以利用这一点,扩展spring的扩展点。在相应的扩展点加入自己的业务初始化代码。从来达到顺序的控制。

具体关于spring容器中大部分的可扩展点的分析,之前已经写了一篇文章详细介绍了:《Springboot启动扩展点超详细总结,再也不怕面试官问了》。

3.4 @AutoConfigureOrder

这个注解用来指定配置文件的加载顺序。但是在实际测试中发现,以下这样使用是不生效的:

@Configuration
@AutoConfigureOrder(2)
public class BeanOrderConfiguration1 {@Beanpublic BeanA beanA(){System.out.println("bean A init");return new BeanA();}
}@Configuration
@AutoConfigureOrder(1)
public class BeanOrderConfiguration2 {@Beanpublic BeanB beanB(){System.out.println("bean B init");return new BeanB();}
}

无论你2个数字填多少,都不会改变其加载顺序结果。

那这个@AutoConfigureOrder到底是如何使用的呢。

经过测试发现,@AutoConfigureOrder只能改变外部依赖的@Configuration的顺序。如何理解是外部依赖呢。

能被你工程内部scan到的包,都是内部的Configuration,而spring引入外部的Configuration,都是通过spring特有的spi文件:spring.factories

换句话说,@AutoConfigureOrder能改变spring.factories中的@Configuration的顺序。

具体使用方式:

@Configuration
@AutoConfigureOrder(10)
public class BeanOrderConfiguration1 {@Beanpublic BeanA beanA(){System.out.println("bean A init");return new BeanA();}
}@Configuration
@AutoConfigureOrder(1)
public class BeanOrderConfiguration2 {@Beanpublic BeanB beanB(){System.out.println("bean B init");return new BeanB();}
}

spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.example.demo.BeanOrderConfiguration1,\com.example.demo.BeanOrderConfiguration2

4.总结

其实在工作中,我相信很多人碰到过复杂的依赖关系的bean加载,把这种不确定性交给spring去做,还不如我们自己去控制,这样在阅读代码的时候 ,也能轻易看出bean之间的依赖先后顺序。

如何正确控制springboot中bean的加载顺序总结相关推荐

  1. 如何控制HTML中DIV的加载顺序

    转载 http://bbl456.blog.sohu.com/72162079.html 目前网站之间相互调用的情况越来越多,比如 需要调用某个第三方提供的一些接口(天气预报),或者是第三方提供的广告 ...

  2. SpringBoot如何正确控制bean的加载顺序

    1. 为什么需要控制bean的加载顺序 springboot遵从约定大于配置的原则,极大程度的解决了配置繁琐的问题.在此基础上,又提供了SPI[Service Provider Interface]机 ...

  3. Springboot之Bean的加载过程

    加载和实例化bean分以下几个重要步骤: 1.根据package扫描出需要被管理的类 2.将这些类封装成BeanDefinition并注册到BeanFactory容器 3.实例化所有扫描到的BeanD ...

  4. 服务器启动时Webapp的web.xml中配置的加载顺序

    一 1.启动一个WEB项目的时候,WEB容器会去读取它的配置文件web.xml,读取<listener>和<context-param>两个结点. 2.紧急着,容创建一个Ser ...

  5. Java 类中各成分加载顺序和内存中的存放位置

    一.什么时候会加载类? 使用到类中的内容时加载:有三种情况 1.创建对象:new StaticCode(); 2.使用类中的静态成员:StaticCode.num=9; StaticCode.show ...

  6. Java类中方法的加载顺序

    1 父类 public class Father {static {System.out.println("父类静态初始化块1");}public static int fsm = ...

  7. SpringBoot profile及其配置文件加载顺序

    1.多Profile文件 Profile是Spring对不同环境提供不同配置功能的支持,可以通过激活.默认使用application.properties的配置: 指定参数等方式快速切换环境 多pro ...

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

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

  9. springboot配置文件加载顺序_「SpringBoot系列」配置文件加载优先级解析

    SpringBoot提供了外部分配置功能,可以使用属性文件(properties).YAML(yml)文件.环境变量和命令行参数来进行处部参数配置,并t以特定的顺序来处理配置,以便于允许合理的覆盖值. ...

最新文章

  1. python字符串进行位运算_不懂python如何使用函数进行分组运算?7种方法,函数分组不再难...
  2. ACS712模块 ACS712ELCTR-05A电流传感器模块
  3. 使用eclipse编写JAVA程序
  4. Scrum 团队成立 -- 软件工程
  5. 2017计算机等级考试题,2017年计算机二级考试题库及答案
  6. 如果不知道做什么,那应该做什么呢?
  7. 深入探讨 java.lang.ref 包
  8. 冲击双一流:燕山大学到底实力如何?
  9. 安装torch_sparse失败解决方法
  10. 客户机操作系统已禁用 cpu_强实时工业互联网虚拟化操作系统Intewell
  11. 读《UNIX 编程艺术》
  12. 高频电子线路——串联谐振、并联谐振总结
  13. php数组中随机抽取,PHP 数组中随机抽取一些元素_PHP教程
  14. linux exclude用法,rsync的include和exclude用法
  15. 锁机制初探(五)Moniter的实现原理
  16. [解决]IDEA每次启动都会打开Licenses激活弹窗、IDEA打不开
  17. ASimpleCache开源缓存框架使用之实现抽签小程序
  18. matlab响应曲面设计,分析响应曲面设计
  19. H5中的label、textarea、select标签
  20. Bitbucket备份恢复

热门文章

  1. 计组头哥实验 第2关 原码一位乘法器设计
  2. 解决虚拟专用网络拨号后本地上网流量都走此网络的问题
  3. 监控系统 Prometheus 的说明
  4. word2vec的pytorch实现
  5. 牛逼的Android UI
  6. 电力监控系统在嘉兴万豪酒店的设计与应用
  7. 详解CAD软件2023功能更新-7个随附专业化工具组合
  8. 让杂牌蓝牙适配器也安装上windows 自带的驱动程序
  9. JVM 内存分哪几个区,每个区的作用是什么
  10. FPGA学习思维导图