首页 文章资讯内容详情

SpringBoot中的bean加载顺序

2026-06-01 2 花语

本文内容纲要:

- - -https://www.dazhuanlan.com/2019/10/22/5daebc5d16429/ -@Order注解 -@AutoConfigureAfter注解 -@DependsOn注解 -属性注入和构造器注入

有几个点需要去琢磨透的:

1、spring.factrores中的configuration跟项目里面自身的configuration一样么(在容器中存储的地方一样么)?

2、spring扫描的顺序会因为什么发生改变?默认是什么样子的顺序,文件加载拍序(跟当前应用所处的系统相关)

3、@Import、factoryBean、@Component、@Bean之间的顺序加载?

4、还有一个平台的platform-hibernate需要去进一步定位问题

https://www.dazhuanlan.com/2019/10/22/5daebc5d16429/

最近在做传统Spring项目到SpringBoot项目迁移过程中,遇到了一些bean加载顺序的问题:

比如一个config中的bean依赖于另一个config中的bean进行初始化,于是查了一些资料,出现了一些新的概念:

@Order @AutoConfigureAfter @DependsOn

@Order注解

BeforeSpring4.0,the@OrderannotationwasusedonlyfortheAspectJexecutionorder.Itmeansthehighestorderadvicewillrunfirst.

SinceSpring4.0,itsupportstheorderingofinjectedcomponentstoacollection.Asaresult,Springwillinjecttheauto-wiredbeansofthesametypebasedontheirordervalue.

在Spring4.0版本之前,@Order注解只能控制AOP的执行顺序,在Spring4.0之后,它还可以控制集合注入中bean的顺序。

控制AOP顺序很好理解,例如可以在@Aspect注解的切面上加入@Order注解,控制切面的执行顺序。

还有@EnableTransactionManagement(order=10),这种写法,由于Spring的事务也是用AOP实现,也可以控制优先级。

下面举个例子说明控制集合注入中bean的顺序。

publicinterface{ intgetRating(); } @Order(1) publicclassExcellentimplements{ @Override publicintgetRating(){ return1; } } @Order(2) publicclassGoodimplements{ @Override publicintgetRating(){ return2; } } @Order(Ordered.LOWEST_PRECEDENCE) publicclassAverageimplements{ @Override publicintgetRating(){ return3; } }

最后是测试类:

publicclassRatingRetrieverUnitTest{ @Autowired privateList<Rating>ratings; @Test publicvoidgivenOrder_whenInjected_thenByOrderValue(){ assertThat(ratings.get(0).getRating(),is(equalTo(1))); assertThat(ratings.get(1).getRating(),is(equalTo(2))); assertThat(ratings.get(2).getRating(),is(equalTo(3))); } }

如果不使用@Order注解,那ratings集合可能是乱序的。

有一种错误的用法:

先定义两个service: @Service publicclassOrderService1{ privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(OrderService1.class); publicOrderService1(){ LOGGER.info("OrderService1constructor"); } publicStringname(){ return"orderService1"; } } @Service publicclassOrderService2{ privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(OrderService2.class); publicOrderService2(){ LOGGER.info("OrderService2constructor"); } publicStringname(){ return"orderService2"; } }

然后写两个config注入bean:

@Configuration @Order(1) publicclassOrderService1Config{ privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(OrderService1Config.class); @Bean publicOrderService1orderService1(){ LOGGER.info("orderService1init"); returnnewOrderService1(); } } @Configuration @Order(0) publicclassOrderService2Config{ privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(OrderService2Config.class); @Bean publicOrderService2orderService2(){ LOGGER.info("orderService2init"); returnnewOrderService2(); } }

本意是想通过@Order控制bean的注入顺序,先注入orderService2,再注入orderService1。但是并没有效果。

所以,@Order注解放到@Configuration中是无法控制bean的注入顺序的。

@AutoConfigureAfter注解

HintforthatanEnableAutoConfigurationauto-configurationshouldbeappliedafterotherspecifiedauto-configurationclasses.

类似的注解还有:

@AutoConfigureBefore @AutoConfigureOrder

这三个注解是特地用于autoconfigure类的,不能用于普通的配置类。

有必要先说明一下autoconfigure类项目。

通常我们会在主类入口上标注@SpringBootApplication注解,或者直接标注@EnableAutoConfiguration注解。

这个注解是用来根据类路径中的依赖包猜测需要注入的bean,实现自动注入:

Enableauto-configurationoftheSpringApplicationContext,attemptingtoguessandconfigurebeansthatyouarelikelytoneed.Auto-configurationclassesareusuallyappliedbasedonyourclasspathandwhatbeansyouhavedefined.

可以理解为,@EnableAutoConfiguration是服务于自动注入的bean的,即spring-boot-starter中bean的自动加载顺序。

被排序的这些类,都是通过xxx-spring-boot-autoconfigure项目中的src/resources/META-INF/spring.factories配置文件获取的,这个文件中的配置内容一般为: #AutoConfigure org.springframework.boot.autoconfigure.EnableAutoConfiguration= com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration

SpringBoot只会对从这个文件读取的配置类进行排序。

但是不要以为将自己的配置类也配置在spring.factories中就能实现排序,如果你的类被自己SpringBoot启动类扫描到了,这个类的顺序会优先于所有通过spring.factories读取的配置类。

Auto-configurationisalwaysappliedafteruser-definedbeanshavebeenregistered.

@DependsOn注解

Beansonwhichthecurrentbeandepends.Anybeansspecifiedareguaranteedtobecreatedbythecontainerbeforethisbean.

Usedinfrequentlyincaseswhereabeandoesnotexplicitlydependonanotherthroughpropertiesorconstructorarguments,butratherdependsonthesideeffectsofanotherbean’sinitialization.

Maybeusedonanyclassdirectlyorindirectlyannotatedwithorg.springframework.stereotype.ComponentoronmethodsannotatedwithBean.

UsingDependsOnattheclasslevelhasnoeffectunlesscomponent-scanningisbeingused.IfaDependsOn-annotatedclassisdeclaredviaXML,DependsOnannotationmetadataisignored,andisrespectedinstead.

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

一般用在一个bean没有通过属性或者构造函数参数显式依赖另外一个bean,但实际上会使用到那个bean或者那个bean产生的某些结果的情况。

用法

直接或者间接标注在带有@Component注解的类上面; 直接或者间接标注在带有@Bean注解的方法上面; 使用@DependsOn注解到类层面仅仅在使用component-scanning方式时才有效;如果带有@DependsOn注解的类通过XML方式使用,该注解会被忽略,<beandepends-on="..."/>这种方式会生效。

例如,我们有一个FileProcessor依赖于FileReader和FileWriter,FileReader和FileWriter需要在FileProcessor之前初始化:

@Configuration @ComponentScan("com.baeldung.dependson") publicclassConfig{ @Bean @DependsOn({"fileReader","fileWriter"}) publicFileProcessorfileProcessor(){ returnnewFileProcessor(); } @Bean("fileReader") publicFileReaderfileReader(){ returnnewFileReader(); } @Bean("fileWriter") publicFileWriterfileWriter(){ returnnewFileWriter(); } }

也可以在Component上标注:

@DependsOn({"filereader","fileWriter"}) publicclassFileProcessor{}

属性注入和构造器注入

上面说到@DependsOn注解时提到,它一般用在一个bean没有通过属性或者构造函数参数显式依赖另外一个bean,但实际上会使用到那个bean或者那个bean产生的某些结果的情况。

如果bean直接依赖于另一个bean,我们可以将其通过属性或者构造函数引入进来。

而使用构造函数的方法显示依赖一个bean,能够保证被依赖的bean先初始化。但是属性注入不可以。

constructor-injectionautomaticallyenforcestheorderandcompletenessoftheinstantiated.

因此,我们可以在Component中使用构造函数显示注入依赖的bean:

@Autowired publicMyComponent(@Qualifier("jedisTemplateNew")JedisTemplatejedisTemplateNew){ }

注意,需要使用@Qualifier限定bean名称时,不能标注在构造方法上,而是应该标注在参数上。原因跟@Resource不能标注构造方法一样,它不知道你要限定哪个参数。

假设有两个service,OrderService1依赖于OrderService2:

publicclassOrderService1{ privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(OrderService1.class); privateOrderService2orderService2; publicOrderService1(OrderService2orderService2){ LOGGER.info("OrderService1constructor"); this.orderService2=orderService2; } publicStringname(){ Stringname=orderService2.name(); LOGGER.info("OrderService1printorderService2name={}",name); return"orderService1"; } } publicclassOrderService2{ privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(OrderService2.class); publicOrderService2(){ LOGGER.info("OrderService2constructor"); } publicStringname(){ return"orderService2"; } }

对应的Configuration:

@Configuration publicclassOrderService1Config{ privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(OrderService1Config.class); @Autowired privateOrderService2ConfigorderService2Config; @Bean publicOrderService1orderService1(){ LOGGER.info("orderService1init"); returnnewOrderService1(orderService2Config.orderService2()); } } @Configuration publicclassOrderService2Config{ privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(OrderService2Config.class); @Bean publicOrderService2orderService2(){ LOGGER.info("orderService2init"); returnnewOrderService2(); } }

输出:

c.m.s.config.OrderService1Config:orderService1init c.m.s.config.OrderService2Config:orderService2init c.m.s.service.OrderService2:OrderService2constructor c.m.s.service.OrderService1:OrderService1constructor

可以看出,OrderService2先初始化。

换一种OrderService1写法,使用属性注入:

publicclassOrderService1{ privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(OrderService1.class); privateOrderService2orderService2; publicvoidsetOrderService2(OrderService2orderService2){ this.orderService2=orderService2; } publicOrderService1(){ LOGGER.info("OrderService1constructor"); } publicStringname(){ Stringname=orderService2.name(); LOGGER.info("OrderService1printorderService2name={}",name); return"orderService1"; } } @Configuration publicclassOrderService1Config{ privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(OrderService1Config.class); @Autowired privateOrderService2ConfigorderService2Config; @Bean publicOrderService1orderService1(){ LOGGER.info("orderService1init"); OrderService1orderService1=newOrderService1(); orderService1.setOrderService2(orderService2Config.orderService2()); returnorderService1; } }

输出:

c.m.s.config.OrderService1Config:orderService1init c.m.s.service.OrderService1:OrderService1constructor c.m.s.config.OrderService2Config:orderService2init c.m.s.service.OrderService2:OrderService2constructor

可以看出,OrderService2并没有先初始化。

当然,OrderService1Config也可以使用构造器注入:

@Configuration publicclassOrderService1Config{ privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(OrderService1Config.class); privatefinalOrderService2ConfigorderService2Config; @Autowired publicOrderService1Config(OrderService2ConfigorderService2Config){ this.orderService2Config=orderService2Config; } @Bean publicOrderService1orderService1(){ LOGGER.info("orderService1init"); OrderService1orderService1=newOrderService1(); orderService1.setOrderService2(orderService2Config.orderService2()); returnorderService1; } }

参考:

@OrderinSpring

ControllingBeanCreationOrderwith@DependsOnAnnotation

本文内容总结:,,https://www.dazhuanlan.com/2019/10/22/5daebc5d16429/,@Order注解,@AutoConfigureAfter注解,@DependsOn注解,属性注入和构造器注入,

原文链接:https://www.cnblogs.com/longxok/p/12021173.html