有几个点需要去琢磨透的:
1、spring.factrores中的configuration跟项目里面自身的configuration一样么(在容器中存储的地方一样么)?
2、spring扫描的顺序会因为什么发生改变?默认是什么样子的顺序,文件加载拍序(跟当前应用所处的系统相关)
3、@Import、factoryBean、@Component、@Bean之间的顺序加载?
4、还有一个平台的platform-hibernate需要去进一步定位问题
最近在做传统Spring项目到SpringBoot项目迁移过程中,遇到了一些bean加载顺序的问题:
比如一个config中的bean依赖于另一个config中的bean进行初始化,于是查了一些资料,出现了一些新的概念:
@Order @AutoConfigureAfter @DependsOnBeforeSpring4.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的注入顺序的。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.PageHelperAutoConfigurationSpringBoot只会对从这个文件读取的配置类进行排序。
但是不要以为将自己的配置类也配置在spring.factories中就能实现排序,如果你的类被自己SpringBoot启动类扫描到了,这个类的顺序会优先于所有通过spring.factories读取的配置类。
Auto-configurationisalwaysappliedafteruser-definedbeanshavebeenregistered.
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