SpringBoot如何正确控制bean的加载顺序
1. 为什么需要控制bean的加载顺序springboot遵从约定大于配置的原则,极大程度的解决了配置繁琐的问题。在此基础上,又提供了SPI【Service Provider Interface】机制,用resources/META-INF/spring.factories配置文件完成一个小组件的自动装配功能。在一般业务场景,可能你不大关心一个bean是如何被注册进spring容器的。只需要把需要
1. 为什么需要控制bean的加载顺序
springboot遵从约定大于配置的原则,极大程度的解决了配置繁琐的问题。在此基础上,又提供了SPI【Service Provider Interface】机制,用resources/META-INF/spring.factories配置文件完成一个小组件的自动装配功能。
在一般业务场景,可能你不大关心一个bean是如何被注册进spring容器的。只需要把需要注册进容器的bean声明为@Component即可,spring会自动扫描到这个Bean完成初始化并加载到spring上下文容器。
当你在项目启动时需要提前做一个业务的初始化工作时,或者你正在开发某个中间件需要完成自动装配时。你会声明自己的Configuration类,但是可能你面对的是好几个有互相依赖的Bean, 如果不加以控制,这时候可能会报找不到依赖的错误。
2. 误区
2.1. 写在前面的先注册
在标注了@Configuration的类中,写在前面的@Bean一定会被先注册
这个不存在的,spring在以前xml的时代,也不存在写在前面一定会被先加载的逻辑。因为xml不是渐进的加载,而是全部parse好,再进行依赖分析和注册。到了springboot中,只是省去了xml被parse成spring内部对象的这一过程,但是加载方式并没有大的改变。
2.2. 按@Order定义的顺序加载
严格的说,不是所有的Bean都可以通过@Order这个标注进行顺序的控制
官方的解释如下:
{@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)
它们不影响单例启动顺序,单例启动顺序是由依赖关系和{@code @DependsOn}声明决定的正交关系(影响运行时确定的依赖关系图)
3. 如何控制顺序
3.1 @DependsOn
@DependsOn注解可以用来控制bean的创建顺序,该注解用于声明当前bean依赖于另外一个bean。所依赖的bean会被容器确保在当前bean实例化之前被实例化。
使用@DependsOn注解到类层面仅仅在使用 component-scanning 方式时才有效,如果带有@DependsOn注解的类通过XML方式使用,该注解会被忽略,这种方式会生效
3.2 参数注入
在@Bean标注的方法上,如果你传入了参数,springboot会自动会为这个参数在spring上下文里寻找这个类型的引用。并先初始化这个类的实例。
利用此特性,也可以控制bean的加载顺序。
@Bean
public BeanA beanA(BeanB b){
System.out.println("bean A init");
return new BeanA();
}
@Bean
public BeanB beanB(){
System.out.println("bean B init");
return new BeanB();
}
3.3 利用bean的生命周期中的扩展点
在spring体系中,从容器到Bean实例化&初始化都是有生命周期的,并且提供了很多的扩展点,允许开发者在这些步骤时进行逻辑的扩展。
这些可扩展点的加载顺序由spring自己控制,大多数是无法进行干预的。可以利用这一点,在相应的扩展点加入自己的业务初始化代码。从来达到顺序的控制。
spring容器中Bean的生命周期内所有可扩展的点的调用顺序:
3.4 @AutoConfigureOrder
这个注解用来指定配置文件的加载顺序.
经过测试发现,@AutoConfigureOrder只能改变外部依赖的@Configuration的顺序。如何理解是外部依赖呢。
能被你工程内部scan到的包,都是内部的Configuration,而spring引入外部的Configuration,都是通过spring特有的spi文件:spring.factories
@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();
}
}
更多推荐
所有评论(0)