@Order注解,你理解錯了!
環(huán)境:SpringBoot3.2.5
1. 簡介
@Order注解是Spring框架中用于定義Bean執(zhí)行順序的優(yōu)先級的一個注解,它位于spring-core包下。這個注解可以應用在類、方法和字段上,其作用是影響B(tài)ean注入到集合中的順序,但不影響B(tài)ean的加載和實例化順序。@Order 注解接受一個整數(shù)值作為參數(shù),數(shù)值越小表示優(yōu)先級越高。需要注意的是,@Order 注解或Ordered接口不能決定Bean的加載順序。
注意:不會影響實例化的順序,實例化的順序是由你注冊(通過掃描時,先發(fā)現(xiàn)的A,那就先實例化A)。
那 @Order 注解到底能用在哪些地方呢?接下來,我們將介紹一些常用場景下使用 @Order 注解的有效方法。
2. 實戰(zhàn)案例
2.1 注入類型為集合
當我們在注入一個集合類型時(有多個相同類型,如一個接口多個實現(xiàn)),我們可以通過@Order注解來控制它們在集合中的順序。
// 定義接口
public interface DAO {
public void save() ;
}
// 下面3個實現(xiàn)類
@Component
public class A implements DAO {
public void save() {
System.out.println("A...") ;
}
}
@Component
public class B implements DAO {
public void save() {
System.out.println("B...") ;
}
}
@Component
public class C implements DAO {
public void save() {
System.out.println("C...") ;
}
}
// 集合注入
@Resource
private List<DAO> daos ;
public void print() {
for (DAO dao : daos) {
dao.save() ;
}
}
運行上面程序,執(zhí)行結果如下:
A...
B...
C...
分別添加@Order注解
@Order(2)
public class A...
@Order(1)
public class B...
@Order(0)
public class C...
再次運行
C...
B...
A...
這里的集合還可以是Array類型。都支持排序。
除了使用@Order注解,你還可以實現(xiàn)Ordered接口。同時,bean的注冊方式也可以是通過配置類@Bean也可以添加@Order注解。
2.2 事件監(jiān)聽ApplicationListener
@Component
@Order(-1)
public class ListenerA implements ApplicationListener<PackEvent> {
@Override
public void onApplicationEvent(PackEvent event) {
System.out.println("A Listener...") ;
}
}
@Component
@Order(-2)
public class ListenerB implements ApplicationListener<PackEvent> {
@Override
public void onApplicationEvent(PackEvent event) {
System.out.println("B Listener...") ;
}
}
當發(fā)布PackEvent事件后,打印順序如下:
B Listener...
A Listener...
同樣你可以實現(xiàn)Ordered接口。
2.3 Application/CommandLineRunner
*Runner接口會在整個Spring Boot啟動完成最后一個階段(Spring容器已經(jīng)完成加載),如下
圖片
圖片
@Component
@Order(0)
public class RunnerA implements CommandLineRunner {
public void run(String... args) throws Exception {
System.out.println("A Runner...") ;
}
}
@Component
@Order(-1)
public class RunnerB implements CommandLineRunner {
public void run(String... args) throws Exception {
System.out.println("B Runner...") ;
}
}
輸出結果
B Runner...
A Runner...
一樣通過配置類注冊或者是實現(xiàn)Ordered接口都可以。
2.4 BeanPostProcessor
這是個Bean處理器(實例化Bean對象前后執(zhí)行回調),我們只能通過實現(xiàn)Ordered接口來控制順序。
public class APostProcessor implements BeanPostProcessor, Ordered {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("A BeanPostProcessor") ;
return bean ;
}
public int getOrder() {
return -1 ;
}
}
public class BPostProcessor implements BeanPostProcessor, Ordered {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("B BeanPostProcessor") ;
return bean ;
}
public int getOrder() {
return -2 ;
}
}
執(zhí)行輸出結果
B BeanPostProcessor
A BeanPostProcessor
目前不支持基于 @Order 注解方式。
除了實現(xiàn)Ordered接口外,你還可以實現(xiàn)PriorityOrdered接口。
2.5 BeanFactoryPostProcessor
該接口與上面的BeanPostProcessor基本一致,你只能通過實現(xiàn)Ordered接口的方式控制順序。
2.6 @Aspect切面
@Aspect
@Order(-1)
public static class AspectA {
@Pointcut("execution(* *(..))")
private void a() {}
@Before("a()")
public void before() {
System.out.println("A before...") ;
}
}
@Aspect
@Order(-2)
public static class AspectB {
@Pointcut("execution(* *(..))")
private void b() {}
@Before("b()")
public void before() {
System.out.println("B before...") ;
}
}
切面執(zhí)行
B before...
A before...
Demo save...
切面除了使用@Order還可以實現(xiàn)Ordered接口。
以上列出了我們工作中比較常用的一些場景使用上可以應用@Order注解或實現(xiàn)Ordered接口。而在Spring Boot環(huán)境下還有很多其它的一些情況都是支持排序的。
2.7 其它
FailureAnalyzer、ApplicationContextInitializer、ErrorPageRegistrar、ErrorViewResolver等。
其實如果是通過如下方式獲取的,都是支持排序的
// 只要是通過該方式獲取對象的,都是支持排序的
SpringFactoriesLoader#load(Class type)