Spring筆記-@Order注解和Ordered接口解析
@Order注解和Ordered接口
Order注解用于排序
public @interface Order { ? ? ? /** ? ? ?* The order value. ? ? ?* <p>Default is {@link Ordered#LOWEST_PRECEDENCE}. ? ? ?* @see Ordered#getOrder() ? ? ?*/ ? ? int value() default Ordered.LOWEST_PRECEDENCE; ? }
1.OrderUtils
Spring提供了OrderUtils來獲取Class的Order注解排序信息
擴展:Priority注解為javax擴展注解,功能與Order相同
public class OrderUtilsTests { ? ? ? @Test ? ? public void getSimpleOrder() { ? ? ? ? assertEquals(Integer.valueOf(50), OrderUtils.getOrder(SimpleOrder.class, null)); ? ? } ? ? ? @Test ? ? public void getPriorityOrder() { ? ? ? ? assertEquals(Integer.valueOf(55), OrderUtils.getOrder(SimplePriority.class, null)); ? ? } ? ? ? @Order(50) ? ? private static class SimpleOrder {} ? ? ? @Priority(55) ? ? private static class SimplePriority {} }
2.Ordered接口
對象排序的另一種實現(xiàn)
public interface Ordered { ? ? int getOrder(); }
3.OrderComparator
使用OrderComparator來比較2個對象的排序順序
public final class OrderComparatorTests { ? ? ? private final OrderComparator comparator = new OrderComparator(); ? ? ? @Test ? ? public void compareOrderedInstancesBefore() { ? ? ? ? assertEquals(-1, this.comparator.compare( ? ? ? ? ? ? ? ? new StubOrdered(100), new StubOrdered(2000))); ? ? } ? ? ? @Test ? ? public void compareOrderedInstancesSame() { ? ? ? ? assertEquals(0, this.comparator.compare( ? ? ? ? ? ? ? ? new StubOrdered(100), new StubOrdered(100))); ? ? } ? ? ? @Test ? ? public void compareOrderedInstancesAfter() { ? ? ? ? assertEquals(1, this.comparator.compare( ? ? ? ? ? ? ? ? new StubOrdered(982300), new StubOrdered(100))); ? ? } ? ? ? private static final class StubOrdered implements Ordered { ? ? ? ? ? private final int order; ? ? ? ? ? public StubOrdered(int order) { ? ? ? ? ? ? this.order = order; ? ? ? ? } ? ? ? ? ? @Override ? ? ? ? public int getOrder() { ? ? ? ? ? ? return this.order; ? ? ? ? } ? ? } ? }
其內(nèi)部比較邏輯
return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
- i1比i2小則返回-1
- i1比i2大則返回1
- i1等于i2則返回0
4.AnnotationAwareOrderComparator
AnnotationAwareOrderComparator繼承自O(shè)rderComparator
其可以同時處理對象實現(xiàn)Ordered接口或@Order注解
其提供了靜態(tài)方法sort,可以對List進行排序
public class AnnotationAwareOrderComparator extends OrderComparator { }
測試代碼
public class AnnotationAwareOrderComparatorTests { ? ? ? @Test ? ? public void sortInstances() { ? ? ? ? List<Object> list = new ArrayList<>(); ? ? ? ? list.add(new B()); ? ? ? ? list.add(new A()); ? ? ? ? AnnotationAwareOrderComparator.sort(list); ? ? ? ? assertTrue(list.get(0) instanceof A); ? ? ? ? assertTrue(list.get(1) instanceof B); ? ? } ? ? ? @Order(1) ? ? private static class A { ? ? } ? ? ? @Order(2) ? ? private static class B { ? ? } }
5.Bean注冊順序
Demo2Config的對象將會先于Demo1Config初始化注冊
注意點:其構(gòu)造函數(shù)的初始化并不生效
@Configuration @Order(2) public class Demo1Config { ? ? ? public Demo1Config() ? ? { ? ? ? ? System.out.println("Demo1Config"); ? ? } ? ? ? @Bean ? ? public Demo1Service demo1Service(){ ? ? ? ? System.out.println("demo1config 加載了"); ? ? ? ? return new Demo1Service(); ? ? } } ? @Configuration @Order(1) public class Demo2Config { ? ? ? public Demo2Config() ? ? { ? ? ? ? System.out.println("Demo2Config"); ? ? } ? ? ? @Bean ? ? public Demo2Service demo2Service(){ ? ? ? ? System.out.println("demo2config 加載了"); ? ? ? ? return new Demo2Service(); ? ? } } ? public class Main { ? ? public static void main(String[] args) { ? ? ? ? AnnotationConfigApplicationContext context = ? ? ? ? ? ? ? ? new AnnotationConfigApplicationContext("core.annotation.order2"); ? ? } ? }
輸出的結(jié)果信息:
Demo1Config
Demo2Config
demo2config 加載了
demo1config 加載了
Spring的Orderd接口及@Order,@Primary,@Priority三個注解介紹
今天要來說一下Orderd接口以及@Order、@Primary、@Priority注解這幾個東西,原本只是想介紹一下@Order,但是這幾個有一定的關(guān)聯(lián),因此這里一起進行介紹。這幾個接口是用來排序,本文主要介紹用法,具體的比如Spring什么時候?qū)λ麄兣判虬?,后面在介紹Spring的處理過程的時候再介紹,還有怎么排序的這些比較好理解的也不介紹了。
1.如何發(fā)現(xiàn)Orderd接口及@Order、@Primary、@Priority
在前面文章說過要通過一些常用的注解以及在學(xué)習(xí)過程中不斷的發(fā)現(xiàn),因此這里我還是按我學(xué)習(xí)的思路介紹一下我是如何發(fā)現(xiàn)他們的。如果沒有一個發(fā)現(xiàn)以及理解的過程有時候可能會很難記住,就比如我之前專門了解了Spring相關(guān)的注解,并且去學(xué)習(xí)用法,但是不理解稍微一不用就忘記了。
首先自己創(chuàng)建一個測試類,創(chuàng)建AnnotationConfigApplicationContext實例。
?? ?@Test ?? ?public void test() { ?? ??? ?ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
進入AnnotationConfigApplicationContext構(gòu)造函數(shù)可以發(fā)現(xiàn)調(diào)用了無參構(gòu)造函數(shù),里面有個創(chuàng)建AnnotatedBeanDefinitionReader的步驟,Spring用BeanDefinition表示一個Bean,因此這個類也很容易理解就是與讀取注解Bean有關(guān)的類。
?? ?public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) { ?? ??? ?super(beanFactory); ?? ??? ?this.reader = new AnnotatedBeanDefinitionReader(this); ?? ??? ?this.scanner = new ClassPathBeanDefinitionScanner(this); ?? ?}
繼續(xù)進入可以看到AnnotatedBeanDefinitionReader的構(gòu)造函數(shù),最后一行表示將那些處理注解的基礎(chǔ)設(shè)施類添加到 DefaultListableBeanFactory中。進入這個方法中。
?? ?public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) { ?? ??? ?Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); ?? ??? ?Assert.notNull(environment, "Environment must not be null"); ?? ??? ?this.registry = registry; ?? ??? ?// 創(chuàng)建條件判斷者,后面用來進行條件注解的判斷,關(guān)聯(lián)@Conditional注解,@Conditional注解內(nèi)傳入的用于判斷的類要實現(xiàn)Condition接口的match方法 ?? ??? ?this.conditionEvaluator = new ConditionEvaluator(registry, environment, null); ?? ??? ?// 將那些處理注解的基礎(chǔ)設(shè)施類添加到 DefaultListableBeanFactory中 ?? ??? ?AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); ?? ?}
方法中有個判斷AnnotationAwareOrderComparator是否存在步驟,這個類從字面意思可以看出就是個比較器。
?? ?public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( ?? ??? ??? ?BeanDefinitionRegistry registry, @Nullable Object source) { ?? ??? ?// 判斷BeanFactory是不是DefaultListableBeanFactory類型,如果不是需要進行轉(zhuǎn)換 ?? ??? ?DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry); ?? ??? ?if (beanFactory != null) { ?? ??? ??? ?// beanFactory的依賴關(guān)系比較器,如果沒有AnnotationAwareOrderComparator這個比較器,就傳入全局默認靜態(tài)不可變的order比較器 ?? ??? ??? ?if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) { ?? ??? ??? ??? ?beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE); ?? ??? ??? ?}
查看這個類的介紹可以看到這個類是OrderComparator的派生,OrderComparator是用來對Orderd或者@Order等內(nèi)部的值進行比較,內(nèi)部源碼我們不做介紹,就是獲取值然后進行數(shù)值的比較。這個類支持Ordered、@Order、@Priority,這些是我們今天要介紹的主要內(nèi)容了,@Primary初始看起來沒有關(guān)聯(lián),后面我們再介紹為什么會有他。
/** ?* {@code AnnotationAwareOrderComparator} is an extension of ?* {@link OrderComparator} that supports Spring's ?* {@link org.springframework.core.Ordered} interface as well as the ?* {@link Order @Order} and {@link javax.annotation.Priority @Priority} ?* annotations, with an order value provided by an {@code Ordered} ?* instance overriding a statically defined annotation value (if any). ?* ?* <p>Consult the Javadoc for {@link OrderComparator} for details on the ?* sort semantics for non-ordered objects. ?* ?* @author Juergen Hoeller ?* @author Oliver Gierke ?* @author Stephane Nicoll ?* @since 2.0.1 ?* @see org.springframework.core.Ordered ?* @see org.springframework.core.annotation.Order ?* @see javax.annotation.Priority ?*/ public class AnnotationAwareOrderComparator extends OrderComparator {
2.Orderd、@Order、@Priority、@Primary
這一個接口和三個注解比較簡單,我粗略介紹一下,不做具體的介紹??偟膩碚f都是用來做bean加載的排序。
- ①orderd接口,實現(xiàn)Oderd接口的話要實現(xiàn)int getOrder();這個方法,返回一個整數(shù)值,值越小優(yōu)先級越高。
- ②@Order里面存儲了一個值,默認為Integer的最大值,同樣值越小優(yōu)先級越高。要注意@Order只能控制組件的加載順序,不能控制注入的優(yōu)先級。但是能控制List 里面存放的XXX的順序,原因是當(dāng)通過構(gòu)造函數(shù)或者方法參數(shù)注入進某個List時,Spring的DefaultListableBeanFactory類會在注入時調(diào)用AnnotationAwareOrderComparator.sort(listA)幫我們?nèi)ネ瓿筛鶕?jù)@Order或者Ordered接口序值排序。@Order更加適用于集合注入的排序。
- ③@Priority與@Order類似,@Order是Spring提供的注解,@Priority是JSR 250標準,同樣是值越小優(yōu)先級越高。但是兩者還是有一定卻別,@Priority能夠控制組件的加載順序,因此@Priority側(cè)重于單個注入的優(yōu)先級排序。此外@Priority優(yōu)先級比@Order更高,兩者共存時優(yōu)先加載@Priority。
- ④@Primary是優(yōu)先級最高的,如果同時有@Primary以及其他幾個的話,@Primary注解的Bean會優(yōu)先加載。
這個優(yōu)先級可以在Spring源碼中的DefaultListableBeanFactory類看出,從下面的代碼可以看到優(yōu)先確定Primary的,然后在根據(jù)權(quán)重來確定,Order與Priority只是不同規(guī)范定義的兩種注解,兩者效果是類似的。這里再額外說一下@Qualifier注解,如果beanName和@Qualifier一致,那么這個優(yōu)先級更高,有興趣的可以自己去源碼探索一下,后面文章也會詳細介紹@Qualifier這個注解。
/** ?? ? * Determine the autowire candidate in the given set of beans. ?? ? * <p>Looks for {@code @Primary} and {@code @Priority} (in that order). ?? ? * @param candidates a Map of candidate names and candidate instances ?? ? * that match the required type, as returned by {@link #findAutowireCandidates} ?? ? * @param descriptor the target dependency to match against ?? ? * @return the name of the autowire candidate, or {@code null} if none found ?? ? */ ?? ?@Nullable ?? ?protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) { ?? ??? ?Class<?> requiredType = descriptor.getDependencyType(); ?? ??? ?String primaryCandidate = determinePrimaryCandidate(candidates, requiredType); ?? ??? ?if (primaryCandidate != null) { ?? ??? ??? ?return primaryCandidate; ?? ??? ?} ?? ??? ?String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType); ?? ??? ?if (priorityCandidate != null) { ?? ??? ??? ?return priorityCandidate; ?? ??? ?} ?? ??? ?// Fallback ?? ??? ?for (Map.Entry<String, Object> entry : candidates.entrySet()) { ?? ??? ??? ?String candidateName = entry.getKey(); ?? ??? ??? ?Object beanInstance = entry.getValue(); ?? ??? ??? ?if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) || ?? ??? ??? ??? ??? ?matchesBeanName(candidateName, descriptor.getDependencyName())) { ?? ??? ??? ??? ?return candidateName; ?? ??? ??? ?} ?? ??? ?} ?? ??? ?return null; ?? ?}
3.測試
測試函數(shù)如下所示,只有簡單的兩行,創(chuàng)建Spring上下文獲取bean,調(diào)用s()方法。具體的實現(xiàn)看OrderTest類。
?? ?@Test ?? ?public void test4() { ?? ??? ?ApplicationContext applicationContext = new AnnotationConfigApplicationContext(OrderTest.class); ?? ??? ?((OrderTest)applicationContext.getBean("orderTest")).test.s(); ?? ?}
①使用兩個@Order注解
如下所示,我們分別給Test1和Test2t設(shè)置@Order為3和2,執(zhí)行后拋出異常,原因是@Order不能控制注入的優(yōu)先級。
@Configuration public class OrderTest { ?? ?public interface Test { ?? ??? ?void s(); ?? ?} ?? ?@Service ?? ?@Order(3) ?? ?public class Test1 implements Test { ?? ??? ?@Override ?? ??? ?public void s() { ?? ??? ??? ?System.out.println(1); ?? ??? ?} ?? ?} ?? ?@Service ?? ?@Order(2) ?? ?public class Test2 implements Test { ?? ??? ?@Override ?? ??? ?public void s() { ?? ??? ??? ?System.out.println(2); ?? ??? ?} ?? ?} ?? ?@Autowired ?? ?public Test test; }
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderTest': Unsatisfied dependency expressed through field 'test'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.huang.config.OrderTest$Test' available: expected single matching bean but found 2: com.huang.config.OrderTest$Test2,com.huang.config.OrderTest$Test1
②使用兩個注解以及一個@Primary注解
我們再上面基于給Test1添加@Primary,由于@Primary優(yōu)先級更高,因此可以控制注入的優(yōu)先級,所以 Test1的實例被注入了,輸出結(jié)果為1。
@Configuration public class OrderTest { ?? ?public interface Test { ?? ??? ?void s(); ?? ?} ?? ?@Service ?? ?@Order(3) ?? ?@Primary ?? ?public class Test1 implements Test { ?? ??? ?@Override ?? ??? ?public void s() { ?? ??? ??? ?System.out.println(1); ?? ??? ?} ?? ?} ?? ?@Service ?? ?@Order(2) ?? ?public class Test2 implements Test { ?? ??? ?@Override ?? ??? ?public void s() { ?? ??? ??? ?System.out.println(2); ?? ??? ?} ?? ?} ?? ?@Autowired ?? ?public Test test; }
1
Process finished with exit code 0
③既有@Order,又有@Priority
既有@Order,又有@Priority時,可以看到雖然@Order的值更小,之前介紹值越小優(yōu)先級越高,但是由于@Priority優(yōu)先級更高,所以注入了Test1。
@Configuration public class OrderTest { ?? ?public interface Test { ?? ??? ?void s(); ?? ?} ?? ?@Service ?? ?@Priority(3) ?? ?public class Test1 implements Test { ?? ??? ?@Override ?? ??? ?public void s() { ?? ??? ??? ?System.out.println(1); ?? ??? ?} ?? ?} ?? ?@Service ?? ?@Order(2) ?? ?public class Test2 implements Test { ?? ??? ?@Override ?? ??? ?public void s() { ?? ??? ??? ?System.out.println(2); ?? ??? ?} ?? ?} ?? ?@Autowired ?? ?public Test test; }
1
Process finished with exit code 0
④兩個@Priority注解
兩個@Priority注解同時存在時,值越小優(yōu)先級越高,因此優(yōu)先注入的是Test2。
@Configuration public class OrderTest { ?? ?public interface Test { ?? ??? ?void s(); ?? ?} ?? ?@Service ?? ?@Priority(4) ?? ?public class Test1 implements Test { ?? ??? ?@Override ?? ??? ?public void s() { ?? ??? ??? ?System.out.println(1); ?? ??? ?} ?? ?} ?? ?@Service ?? ?@Priority(3) ?? ?public class Test2 implements Test { ?? ??? ?@Override ?? ??? ?public void s() { ?? ??? ??? ?System.out.println(2); ?? ??? ?} ?? ?} ?? ?@Autowired ?? ?public Test test; }
2
Process finished with exit code 0
⑤使用@Order控制集合注入
修改要注入的為Test集合
@Configuration public class OrderTest { ?? ?public interface Test { ?? ??? ?void s(); ?? ?} ?? ?@Service ?? ?@Order(2) ?? ?public class Test1 implements Test { ?? ??? ?@Override ?? ??? ?public void s() { ?? ??? ??? ?System.out.println(1); ?? ??? ?} ?? ?} ?? ?@Service ?? ?@Order(1) ?? ?public class Test2 implements Test { ?? ??? ?@Override ?? ??? ?public void s() { ?? ??? ??? ?System.out.println(2); ?? ??? ?} ?? ?} ?? ?@Autowired ?? ?public List<Test> testList; }
修改測試代碼
?? ?@Test ?? ?public void test4() { ?? ??? ?ApplicationContext applicationContext = new AnnotationConfigApplicationContext(OrderTest.class); ?? ??? ?((OrderTest)applicationContext.getBean("orderTest")).testList.get(0).s(); ?? ?}
執(zhí)行結(jié)果如下所示,可以看到@Order值小的,優(yōu)先級更高,在集合的前邊。
2
Process finished with exit code 0
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
spring mvc 讀取xml文件數(shù)據(jù)庫配置參數(shù)的方法
下面小編就為大家?guī)硪黄猻pring mvc 讀取xml文件數(shù)據(jù)庫配置參數(shù)的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10maven打包web項目時同時打包為war和jar文件的方法
本篇文章主要介紹了maven打包web項目時同時打包為war和jar文件的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-10-10Idea開發(fā)工具之SpringBoot整合JSP的過程
最近在學(xué)習(xí)SpringBoot,看到SpringBoot整合jsp,順帶記錄一下。本文通過圖文實例相結(jié)合給大家講解SpringBoot整合JSP的過程,感興趣的朋友一起看看吧2021-09-09java基于netty NIO的簡單聊天室的實現(xiàn)
這篇文章主要介紹了java基于netty NIO的簡單聊天室的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07Maven在Java8下如何忽略Javadoc的編譯錯誤詳解
這篇文章主要給大家介紹了關(guān)于Maven在Java8下如何忽略Javadoc的編譯錯誤的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-08-08