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

Spring Bean 加载的执行顺序 InitializingBean 接口 @PostConstruct 注解 执行顺序 DisposableBean 接口 @PreDestroy 注解 执行顺序 理解记忆:Java 注解 > Spring 接口 > Spring 注解 Java 注解: @PostConstruct / @PreDestroy Spring 接口: InitializingBean / DisposableBean Spring 注解: @Bean (initMethod / destroyMethod) 阅读详情
AI摘要

本文深入探讨SpringBoot中Bean加载顺序的控制方法,包括@DependsOn、参数注入、利用bean生命周期扩展点及@AutoConfigureOrder等技巧,帮助解决复杂依赖关系。


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


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

4.总结

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


万字长文!带你探索 Bean 加载流程 为了让 Spring IoC 容器正确地完成 Bean 加载流程,必须要有一个数据模型来承载 Bean 的配置元数据,配置元数据可以告诉 Spring IoC 容器如何创建 Bean 实例何时创建 Bean 实例和Bean 的生命周期细节等信息,这个数据模型就是接口,在其众多实现类中,RootBeanDefinition 最为常用!在 Spring Boot 中,BeanDefinition 可以归纳为两类:一种是由开发人员声明的,另一种是由官方及第三方起步依赖starter。 阅读详情

相关推荐

【微服务】spring 控制bean加载顺序使用详解

spring 控制bean加载顺序使用详解

congge 6894

Sprin中Bean的顺序

Bean加载顺序、执行顺序

u014365523的博客 1万+

TDR阻抗会爬坡? 别担心,不是你的错,你只是不够了解TDR!

TDR除了可以单靠一个Port就得到通道的阻抗外,其实也可以拿来计算传输线的Delay,或是两两对象之间的距离,甚至是拿来求得等效介电常数!

jkh920184196的博客 2159

springboot中bean的加载顺序

1、为什么要控制spring的加载顺序 当你在项目启动时需要提前做一个业务的初始化工作时,或者你正在开发某个中间件需要完成自动装配时。你会声明自己的Configuration类,但是可能你面对的是好几个有互相依赖的Bean。如果不加以控制,这时候可能会报找不到依赖的错误,这个时候需要通过一些手段来控制springboot中的bean加载顺序。 2、如何控制Spring的加载顺序 ...

weixin_44792849的博客 7390

记一次从零到getshell的渗透历程

0x00 前期 拿到测试范围清单后,首先用脚本获取了下各个子站的标题,基本都是XXX管理系统。浏览器查看后,各个子站也大同小异,纯登录系统,带验证码。这些系统基本都是jsp写的,逮到了两个没有验证码的小宝贝,一番暴力破解,小宝贝对我说:别爱我,没结果。又看到了两个站返回的Set-Cookie头:rememberMe=deleteMe; 很明显,这是Apache Shiro。打了一波exp,没有反应,放弃。搞了三天啥都没搞出来,和女朋友出去玩散散心,还是很高兴。 0x01 初显进展 测试范围内有六个门户

CanMeng'Blog - 一个WEB安全渗透的技术爱好者 3970

三相逆变器LCL滤波设计实战:从αβ转换到dq解耦控制的完整建模流程

本文详细解析了三相逆变器LCL滤波设计中的关键步骤,从αβ转换到dq解耦控制的完整建模流程。重点介绍了dq坐标系下的解耦控制策略,通过Simulink仿真验证模型准确性,并提供谐振峰偏移、解耦不彻底等实际问题的解决方案,助力电力电子工程师提升系统稳定性。

weixin_28678151的博客 230

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

1. 为什么需要控制bean的加载顺序 springboot遵从约定大于配置的原则,极大程度的解决了配置繁琐的问题。在此基础上,又提供了SPI【Service Provider Interface】机制,用resources/META-INF/spring.factories配置文件完成一个小组件的自动装配功能。 在一般业务场景,可能你不大关心一个bean是如何被注册进spring容器的。只需要把需要注册进容器的bean声明为@Component即可,spring会自动扫描到这个Bean完成初始化并加载到s

penriver的博客 4957

锁定放大器

锁定放大器

qq_46757048的博客 4706

springboot配置文件加载顺序_SpringBoot系列教程之Bean加载顺序之错误使用姿势辟谣...

转自:小灰灰blog在网上查询 Bean 的加载顺序时,看到了大量的文章中使用@Order注解的方式来控制 bean 的加载顺序,不知道写这些的博文的同学自己有没有实际的验证过,本文希望通过指出这些错误的使用姿势,让观文的小伙伴可以知道@Order的具体的应用场景I. 环境搭建 创建一个 maven 项目,pom 文件如下(具体的项目代码,可以在文末获取)<parent> ...

weixin_39634022的博客 226

深入解析UVM寄存器模型:reg2bus与bus2reg的隐式调用机制

本文深入解析了UVM寄存器模型中reg2bus与bus2reg函数的隐式调用机制。通过追踪一次寄存器访问的完整旅程,揭示了这两个关键函数是如何在uvm_reg_map和uvm_reg_predictor中被框架自动调用的,从而在抽象的寄存器操作与具体总线事务之间完成转换,并实现镜像值的自动更新。掌握此机制是高效调试和灵活应用UVM寄存器模型的基础。

weixin_29211309的博客 441

WPF毛玻璃效果别再写C#代码了!纯XAML用Border+VisualBrush+BlurEffect三步搞定

本文详细介绍了如何在WPF中通过纯XAML实现毛玻璃效果,无需编写C#代码。通过VisualBrush、BlurEffect和Clip的黄金组合,开发者可以快速创建专业级的毛玻璃面板,提升UI的现代感和视觉层次。文章还提供了性能优化技巧和实战案例,帮助开发者在各种场景中高效应用这一技术。

weixin_28630185的博客 353

spring bean加载顺序问题

顺序:意思是依次而不乱。顺序在生活的方方面面都显得尤为重要,自然的它对程序执行来说也是至关重要的。有了顺序的保证,我们就能对“结果”做出预期,作为coder的我们对应的也就更能“掌控”自己所写代码,心里也就更加踏实。顺序固然重要,但是不乏有些场景它是不需要顺序保证的。一般来说:无序的效率会比顺序高,毕竟保证顺序是需要花费资源的(人力、物理、时间…)。本文将主要讨论Spring在实例化Bean时的顺序性,以及我们如何才能“控制”这种顺序呢?

Jayce的博客 2558

华为OD机试真题 新系统2026-04-08 C++ 实现【直捣黄龙】

小王在玩一款叫做直捣黄龙的小游戏,在该游戏中他需要从入口位置进入敌营,绕过哨兵的层层封锁,达到敌军司令部实施斩首行动。 敌军阵营是一个n*n的矩阵,入口在坐标(0,n/2),敌军司令部在坐标(n-1,n/2),每个 哨兵警戒以自己为中心的9宫格,一旦被哨兵发现则行动失败。

MISAYAONE的博客 262

Spring Bean加载顺序的控制

Spring Bean加载顺序的控制,最终测试结果为:一般情况下会按照SPring类的书写的顺序去创建,但是也不一定,最终其实得看你的编译出来的文件,的Class文件到底是什么样子的,包括操作系统文件的排序规则等一系列的因素。

qq_48025216的博客 3376

RK3568平台开发系列讲解:Linux wifi的调试

查询结果中state为ENABLE,表示hostapd程序启用成功。首先查看设备是否存在。

内核笔记 168

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Spring-Boot-Bean加载顺序之错误使用姿势辟谣

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

Java程序员的知识博客 1275

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

上一篇: 工商银行 MySQL 数据库架构解密
下一篇: 为什么我们选择基于 Flink 搭建实时个性化营销平台?
qianshanding0708
博客等级 码龄11年 428粉丝 96原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值