<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Order註解用於排序
public @interface Order { /** * The order value. * <p>Default is {@link Ordered#LOWEST_PRECEDENCE}. * @see Ordered#getOrder() */ int value() default Ordered.LOWEST_PRECEDENCE; }
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 {} }
物件排序的另一種實現
public interface Ordered { int getOrder(); }
使用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; } } }
其內部比較邏輯
return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
AnnotationAwareOrderComparator繼承自OrderComparator
其可以同時處理物件實現Ordered介面或@Order註解
其提供了靜態方法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 { } }
Demo2Config的物件將會先於Demo1Config初始化註冊
注意點:其建構函式的初始化並不生效
@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"); } }
輸出的結果資訊:
Demo1Config
Demo2Config
demo2config 載入了
demo1config 載入了
今天要來說一下Orderd介面以及@Order、@Primary、@Priority註解這幾個東西,原本只是想介紹一下@Order,但是這幾個有一定的關聯,因此這裡一起進行介紹。這幾個介面是用來排序,本文主要介紹用法,具體的比如Spring什麼時候對他們排序啊,後面在介紹Spring的處理過程的時候再介紹,還有怎麼排序的這些比較好理解的也不介紹了。
在前面文章說過要通過一些常用的註解以及在學習過程中不斷的發現,因此這裡我還是按我學習的思路介紹一下我是如何發現他們的。如果沒有一個發現以及理解的過程有時候可能會很難記住,就比如我之前專門瞭解了Spring相關的註解,並且去學習用法,但是不理解稍微一不用就忘記了。
首先自己建立一個測試類,建立AnnotationConfigApplicationContext範例。
@Test public void test() { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
進入AnnotationConfigApplicationContext建構函式可以發現呼叫了無參建構函式,裡面有個建立AnnotatedBeanDefinitionReader的步驟,Spring用BeanDefinition表示一個Bean,因此這個類也很容易理解就是與讀取註解Bean有關的類。
public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) { super(beanFactory); this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); }
繼續進入可以看到AnnotatedBeanDefinitionReader的建構函式,最後一行表示將那些處理註解的基礎設施類新增到 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; // 建立條件判斷者,後面用來進行條件註解的判斷,關聯@Conditional註解,@Conditional註解內傳入的用於判斷的類要實現Condition介面的match方法 this.conditionEvaluator = new ConditionEvaluator(registry, environment, null); // 將那些處理註解的基礎設施類新增到 DefaultListableBeanFactory中 AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); }
方法中有個判斷AnnotationAwareOrderComparator是否存在步驟,這個類從字面意思可以看出就是個比較器。
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( BeanDefinitionRegistry registry, @Nullable Object source) { // 判斷BeanFactory是不是DefaultListableBeanFactory型別,如果不是需要進行轉換 DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry); if (beanFactory != null) { // beanFactory的依賴關係比較器,如果沒有AnnotationAwareOrderComparator這個比較器,就傳入全域性預設靜態不可變的order比較器 if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) { beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE); }
檢視這個類的介紹可以看到這個類是OrderComparator的派生,OrderComparator是用來對Orderd或者@Order等內部的值進行比較,內部原始碼我們不做介紹,就是獲取值然後進行數值的比較。這個類支援Ordered、@Order、@Priority,這些是我們今天要介紹的主要內容了,@Primary初始看起來沒有關聯,後面我們再介紹為什麼會有他。
/** * {@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 {
這一個介面和三個註解比較簡單,我粗略介紹一下,不做具體的介紹。總的來說都是用來做bean載入的排序。
這個優先順序可以在Spring原始碼中的DefaultListableBeanFactory類看出,從下面的程式碼可以看到優先確定Primary的,然後在根據權重來確定,Order與Priority只是不同規範定義的兩種註解,兩者效果是類似的。這裡再額外說一下@Qualifier註解,如果beanName和@Qualifier一致,那麼這個優先順序更高,有興趣的可以自己去原始碼探索一下,後面文章也會詳細介紹@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; }
測試函數如下所示,只有簡單的兩行,建立Spring上下文獲取bean,呼叫s()方法。具體的實現看OrderTest類。
@Test public void test4() { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(OrderTest.class); ((OrderTest)applicationContext.getBean("orderTest")).test.s(); }
①使用兩個@Order註解
如下所示,我們分別給Test1和Test2t設定@Order為3和2,執行後丟擲異常,原因是@Order不能控制注入的優先順序。
@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優先順序更高,因此可以控制注入的優先順序,所以 Test1的範例被注入了,輸出結果為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的值更小,之前介紹值越小優先順序越高,但是由於@Priority優先順序更高,所以注入了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註解同時存在時,值越小優先順序越高,因此優先注入的是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(); }
執行結果如下所示,可以看到@Order值小的,優先順序更高,在集合的前邊。
2
Process finished with exit code 0
以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45