当前位置: 首页 > news >正文

java spring 加载顺序_java编程之如何控制springboot中bean的加载顺序

控制加载顺序的目的

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

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

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

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

加载bean的几个误区

在正式说如何控制加载顺序之前,先说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实现类的加载顺序

控制bean的加载顺序的方法

@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();

}

@Bean

public 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();

}

@Bean

public 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标注的方法上,如果你传入了参数,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的名称”)来指定。

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

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

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

@AutoConfigureOrder

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

@Configuration

@AutoConfigureOrder(2)

public class BeanOrderConfiguration1 {

@Bean

public BeanA beanA(){

System.out.println("bean A init");

return new BeanA();

}

}

@Configuration

@AutoConfigureOrder(1)

public class BeanOrderConfiguration2 {

@Bean

public 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 {

@Bean

public BeanA beanA(){

System.out.println("bean A init");

return new BeanA();

}

}

@Configuration

@AutoConfigureOrder(1)

public class BeanOrderConfiguration2 {

@Bean

public 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

相关文章:

  • java注册用户信息_界面设计之注册用户信息
  • java 解析der文件_[Java]读取文件方法大全
  • java中成员变量的分类_Java基础—变量分类、类与对象
  • java语言字符串代码_JAVA语言实现字符串排序的代码教程
  • java findcontour_cvFindContours获取轮廓数目和轮廓图像
  • java if 没有_使用if语句时,为什么我的代码没有给出正确的答案? - java
  • php时间格式转换成时间戳,php时间格式转换成时间戳的方法
  • echarts php 数据处理,PHP 使用Echarts生成数据统计报表详解
  • conv php,php metaphone()函数及php localeconv() 函数实例解析
  • php 配置 error_reporting,关于php中的错误配置display_errors与error_reporting说明
  • php计算器源码,php 简单计算器
  • 学生考勤管理系统php,php158 学生考勤管理系统
  • linux php-mbstring下载,linux下php加载mbstring的方法 | 快享
  • php 與或非,js逻辑与,或,非
  • java邮件代码,java发送邮件(示例代码)
  • 《Javascript数据结构和算法》笔记-「字典和散列表」
  • 【vuex入门系列02】mutation接收单个参数和多个参数
  • 2017前端实习生面试总结
  • canvas绘制圆角头像
  • eclipse(luna)创建web工程
  • Java多线程(4):使用线程池执行定时任务
  • leetcode-27. Remove Element
  • node-glob通配符
  • 从零到一:用Phaser.js写意地开发小游戏(Chapter 3 - 加载游戏资源)
  • 从输入URL到页面加载发生了什么
  • 分布式熔断降级平台aegis
  • 工作中总结前端开发流程--vue项目
  • 删除表内多余的重复数据
  • 听说你叫Java(二)–Servlet请求
  • 一些基于React、Vue、Node.js、MongoDB技术栈的实践项目
  • 与 ConTeXt MkIV 官方文档的接驳
  • 看到一个关于网页设计的文章分享过来!大家看看!
  • 完善智慧办公建设,小熊U租获京东数千万元A+轮融资 ...
  • #14vue3生成表单并跳转到外部地址的方式
  • #QT(智能家居界面-界面切换)
  • (JSP)EL——优化登录界面,获取对象,获取数据
  • (Matalb回归预测)PSO-BP粒子群算法优化BP神经网络的多维回归预测
  • (十三)Java springcloud B2B2C o2o多用户商城 springcloud架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)...
  • (四)c52学习之旅-流水LED灯
  • (算法)N皇后问题
  • (五)网络优化与超参数选择--九五小庞
  • (新)网络工程师考点串讲与真题详解
  • ..thread“main“ com.fasterxml.jackson.databind.JsonMappingException: Jackson version is too old 2.3.1
  • .NET Framework、.NET Core 、 .NET 5、.NET 6和.NET 7 和.NET8 简介及区别
  • .net framwork4.6操作MySQL报错Character set ‘utf8mb3‘ is not supported 解决方法
  • .Net 垃圾回收机制原理(二)
  • .net遍历html中全部的中文,ASP.NET中遍历页面的所有button控件
  • .NET简谈设计模式之(单件模式)
  • .NET性能优化(文摘)
  • /etc/X11/xorg.conf 文件被误改后进不了图形化界面
  • @Service注解让spring找到你的Service bean
  • []C/C++读取串口接收到的数据程序
  • [BZOJ3757] 苹果树
  • [C++] 模拟实现list(二)
  • [dts]Device Tree机制