关于Spring中@Order 、@AutoConfigureBefore等与顺序相关注解的使用误区
关于Spring中@Order 、@AutoConfigureBefore等与顺序相关注解的误区
1、@Order注解并非一定会给你的bean排序
@Order注解表示排序,但是它不能决定@Configuration或者是@Bean注解的实例化顺序。决定Spring里bean实例化或者注入顺序的一般情况下是bean之间的依赖关系。这个依赖关系一般是类的构造函数的参数、类属性或者@DependsOn注解来控制。
以下是错误的演示,Test1Config和Test2Config两个配置类的实例化,包括Apple和Orange的实例化都无法用@Order注解控制,调换顺序后可以发现实例化的顺序不会变化,因为他们之间并没有依赖关系。
@Configuration
@Order(100)
public class Test1Config {
public Test1Config() {
System.out.println("Test1Config 构造");
}
@Bean
public Apple apple(){
System.out.println("准备new Apple ...");
return new Apple();
}
}
@Configuration
@Order(0)
public class Test2Config {
public Test2Config() {
System.out.println("Test2Config 构造");
}
@Bean
public Orange orange(){
System.out.println("准备new Orange ...");
return new Orange();
}
}
2、那么如何控制配置类以及Bean的实例化顺序呢?
在实际项目中,我们确实有需要控制某几个类的注入IOC容器的顺序,一般如果有直接依赖关系可以用类属性或者构造函数方式实现,一般推荐类属性注入,因为Spring并没有解决构造函数注入的循环依赖问题,所以没有十分的把握不要采用构造函数注入。
如果Bean之间其实没有直接引用依赖关系,但是又要控制两个Bean之间的注入顺序,可以使用@DependsOn注解。比如上面的例子,假设Test2Config需要先实例化注入到IOC容器,可以采用如下方式:
@Configuration
@DependsOn("test2Config")
public class Test1Config {
public Test1Config() {
System.out.println("Test1Config 构造");
}
@Bean
public Apple apple(){
System.out.println("准备new Apple ...");
return new Apple();
}
}
3、那么@Order注解如何正确使用?
@Order注解只会给Spring实现其排序功能的组件或者接口中发挥作用,又或者由开发者自定义其顺序的实现。比如:Spring的接口CommandLineRunner就可以支持@Order注解,在我们实现多个CommandLineRunner接口的时候,如果对其执行顺序有要求的时候,就可以使用@Order注解。
@Component
@Order(160)
public class AppleCommand implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("AppleCommand run ...");
}
}
@Component
@Order(150)
public class OrangeCommand implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("OrangeCommand run ...");
}
}
调整两段代码@Order的大小,可以调整其执行先后顺序。
对于@Order注解,可以参考官方解释,深刻理解其含义和应用。
NOTE: 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 @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 @DependsOn declarations (influencing a runtime-determined dependency graph).
4、@AutoConfigureBefore是给自动配置排序用的
@AutoConfigureBefore、@AutoConfigureAfter、@AutoConfigureOrder这三个注解是给Springboot自动配置类排序使用的,注意是自动配置类,并非是普通的配置类。
Springboot的自动配置需要在jar包目录下META-INF/spring.factories
文件中进行类名配置。类似:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.wood.lib.autoconfigure.AXXXAutoConfiguration,\
com.wood.lib.autoconfigure.BXXXWebAutoConfiguration
注:自动配置类只能通过这种方式加载,确保它们定义在一个特殊的package中,特别是不能成为组件扫描的目标。
这样你可以使用@AutoConfigureAfter
或@AutoConfigureBefore
注解为配置类指定特定的顺序。如下:
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(SecurityProperties.class)
@ConditionalOnClass({ AbstractSecurityWebApplicationInitializer.class, SessionCreationPolicy.class })
@AutoConfigureAfter(BXXXWebAutoConfiguration.class)
public class AXXXAutoConfiguration {
@Bean
@ConditionalOnBean(name = DEFAULT_FILTER_NAME)
public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(
SecurityProperties securityProperties) {
...
return registration;
}
... ...
}