您好,登錄后才能下訂單哦!
這篇文章主要介紹“怎么用Spring中的@Order進(jìn)行排序”的相關(guān)知識,小編通過實(shí)際案例向大家展示操作過程,操作方法簡單快捷,實(shí)用性強(qiáng),希望這篇“怎么用Spring中的@Order進(jìn)行排序”文章能幫助大家解決問題。
直接上代碼
public class OrderAnnotationTest { public static void main(String[] args) { A a = new A(); B b = new B(); C c = new C(); List<Object> orderList = new ArrayList<>(3); orderList.add(a); orderList.add(b); orderList.add(c); orderList.sort(AnnotationAwareOrderComparator.INSTANCE); System.out.println(orderList); } @Order(0) static class A { @Override public String toString() { return "A"; } } @Order(-1) static class B { @Override public String toString() { return "B"; } } @Order(2) static class C { @Override public String toString() { return "C"; } } }
結(jié)果如下:
[B, A, C]
原理解析:
AnnotationAwareOrderComparator繼承自O(shè)rderComparator
實(shí)際比較的方法如下
private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderSourceProvider sourceProvider) { boolean p1 = (o1 instanceof PriorityOrdered); boolean p2 = (o2 instanceof PriorityOrdered); if (p1 && !p2) { return -1; } else if (p2 && !p1) { return 1; } int i1 = getOrder(o1, sourceProvider); int i2 = getOrder(o2, sourceProvider); return Integer.compare(i1, i2); }
本文閱讀源碼版本為spring5.3.1
spring是一個(gè)大量使用策略設(shè)計(jì)模式的框架,這意味著有很多相同接口的實(shí)現(xiàn)類,如果不手動指定順序的話,那么使用時(shí)肯定會有問題。而Order給我們提供了一種編碼設(shè)置順序的可能。
spring中提供了多種方式來設(shè)置優(yōu)先級,有Ordered,PriorityOrdered接口,有Order注解,除此之外,spring4.1以后,還可以使用Priority注解。下面我將針對這幾種用法從源碼的角度來進(jìn)行分析。
Ordered,PriorityOrdered接口
public interface Ordered { /** * 最高優(yōu)先值 */ int HIGHEST_PRECEDENCE = Integer.MIN_VALUE; /** * 最低優(yōu)先值 */ int LOWEST_PRECEDENCE = Integer.MAX_VALUE; int getOrder(); }
PriorityOrdered繼承了Ordered,但并未提供任何方法,這是一個(gè)標(biāo)記了優(yōu)先級的接口,和Ordered相比,PriorityOrdered就是高人一等,spring中提供了比較器OrderComparator,可以通過構(gòu)建一個(gè)OrderComparator,調(diào)用其compare方法,不過OrderComparator提供了一個(gè)靜態(tài)sort方法,我們無需自己構(gòu)建OrderComparator了,排序的結(jié)果按照order值從小到大排序。
demo
public class OrderDemo{ private final OrderComparator comparator = new OrderComparator(); @Test void comparePriorityOrderedInstanceToStandardOrderedInstanceWithSamePriority() { assertThatPriorityOrderedAlwaysWins(new StubPriorityOrdered(100), new StubOrdered(100)); } @Test void comparePriorityOrderedInstanceToStandardOrderedInstanceWithLowerPriority() { assertThatPriorityOrderedAlwaysWins(new StubPriorityOrdered(100), new StubOrdered(200)); } @Test void compareOrderedInstancesBefore() { assertThat(this.comparator.compare(new StubOrdered(100), new StubOrdered(2000))).isEqualTo(-1); } @Test void compareOrderedInstancesNullFirst() { assertThat(this.comparator.compare(null, new StubOrdered(100))).isEqualTo(1); } @Test void compareOrderedInstancesNullLast() { assertThat(this.comparator.compare(new StubOrdered(100), null)).isEqualTo(-1); } @Test void test1() { assertThat(this.comparator.compare(new Object (), new StubOrdered(2000))).isEqualTo(1); } private static class StubOrdered implements Ordered { private final int order; StubOrdered(int order) { this.order = order; } @Override public int getOrder() { return this.order; } } private static class StubPriorityOrdered implements PriorityOrdered { private final int order; StubPriorityOrdered(int order) { this.order = order; } @Override public int getOrder() { return this.order; } } }
小結(jié)
PriorityOrdered優(yōu)先級比Ordered高,與設(shè)置的order值無關(guān)。
若兩個(gè)對象都實(shí)現(xiàn)了Ordered或PriorityOrdered接口,那么設(shè)置的order值越小,優(yōu)先值越高。
若沒有實(shí)現(xiàn)Ordered或PriorityOrdered接口,默認(rèn)是最低的優(yōu)先級。
在看compare之前,我覺得將OrderSourceProvider這個(gè)函數(shù)式接口放在前面講解一下,閱讀源碼時(shí)會更清晰一點(diǎn)。
@FunctionalInterface public interface OrderSourceProvider { /** * 對給定對象校驗(yàn)并返回一個(gè)新的對象 */ @Nullable Object getOrderSource(Object obj); }
demo
public class OrderDemo{ private final OrderComparator comparator = new OrderComparator(); private static class TestSourceProvider implements OrderComparator.OrderSourceProvider { private final Object target; private final Object orderSource; TestSourceProvider(Object target, Object orderSource) { this.target = target; this.orderSource = orderSource; } @Override public Object getOrderSource(Object obj) { if (target.equals(obj)) { return orderSource; } return null; } } @Test void compareWithSourceProviderArray() { Comparator<Object> customComparator = this.comparator.withSourceProvider( new TestSourceProvider(5L, new Object[] {new StubOrdered(10), new StubOrdered(-25)})); assertThat(customComparator.compare(5L, new Object())).isEqualTo(-1); } @Test void compareWithSourceProviderArrayNoMatch() { Comparator<Object> customComparator = this.comparator.withSourceProvider( new TestSourceProvider(5L, new Object[] {new Object(), new Object()})); assertThat(customComparator.compare(new Object(), 5L)).isEqualTo(0); } @Test void compareWithSourceProviderEmpty() { Comparator<Object> customComparator = this.comparator.withSourceProvider( new TestSourceProvider(50L, new Object())); assertThat(customComparator.compare(new Object(), 5L)).isEqualTo(0); } }
接下來我們來閱讀compare源碼。
public int compare(@Nullable Object o1, @Nullable Object o2) { return doCompare(o1, o2, null); } private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderSourceProvider sourceProvider) { // 這里會判斷是否實(shí)現(xiàn)了PriorityOrdered接口 boolean p1 = (o1 instanceof PriorityOrdered); boolean p2 = (o2 instanceof PriorityOrdered); // 這里會看到根本沒有比較order的值,只要實(shí)現(xiàn)PriorityOrdered接口,就會排在前面 if (p1 && !p2) { return -1; }else if (p2 && !p1) { return 1; } // 獲取對象設(shè)置的order值 int i1 = getOrder(o1, sourceProvider); int i2 = getOrder(o2, sourceProvider); return Integer.compare(i1, i2); } private int getOrder(@Nullable Object obj, @Nullable OrderSourceProvider sourceProvider) { Integer order = null; if (obj != null && sourceProvider != null) { Object orderSource = sourceProvider.getOrderSource(obj); if (orderSource != null) { // 如果返回的是數(shù)組 if (orderSource.getClass().isArray()) { for (Object source : ObjectUtils.toObjectArray(orderSource)) { // 只要找到對象設(shè)置的order值,就跳出 order = findOrder(source); if (order != null) { break; } } }else { order = findOrder(orderSource); } } } // 如果我們沒有提供OrderSourceProvider return (order != null ? order : getOrder(obj)); } protected int getOrder(@Nullable Object obj) { if (obj != null) { Integer order = findOrder(obj); if (order != null) { return order; } } // object為null時(shí),返回值最大 return Ordered.LOWEST_PRECEDENCE; } protected Integer findOrder(Object obj) { // 沒有實(shí)現(xiàn)Ordered接口將返回null return (obj instanceof Ordered ? ((Ordered) obj).getOrder() : null); }
spring中提供了對@Order與@Priority支持的比較器AnnotationAwareOrderComparator,該類繼承OrderComparator,并覆蓋了findOrder方法,我們來一起看下源碼。
protected Integer findOrder(Object obj) { Integer order = super.findOrder(obj); if (order != null) { return order; } // 調(diào)用父類的findOrder方法無法找到設(shè)定的order值時(shí) return findOrderFromAnnotation(obj); } private Integer findOrderFromAnnotation(Object obj) { AnnotatedElement element = (obj instanceof AnnotatedElement ? (AnnotatedElement) obj : obj.getClass()); // 對整個(gè)類型層次結(jié)構(gòu)執(zhí)行完整搜索,包括父類和接口 MergedAnnotations annotations = MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY); // 獲取注解中設(shè)置的order值 Integer order = OrderUtils.getOrderFromAnnotations(element, annotations); if (order == null && obj instanceof DecoratingProxy) { return findOrderFromAnnotation(((DecoratingProxy) obj).getDecoratedClass()); } return order; } static Integer getOrderFromAnnotations(AnnotatedElement element, MergedAnnotations annotations) { if (!(element instanceof Class)) { return findOrder(annotations); } // 加入緩存中 Object cached = orderCache.get(element); if (cached != null) { return (cached instanceof Integer ? (Integer) cached : null); } Integer result = findOrder(annotations); orderCache.put(element, result != null ? result : NOT_ANNOTATED); return result; } // 沒有找到Order注解后才去尋找@Priority注解 private static Integer findOrder(MergedAnnotations annotations) { MergedAnnotation<Order> orderAnnotation = annotations.get(Order.class); if (orderAnnotation.isPresent()) { return orderAnnotation.getInt(MergedAnnotation.VALUE); } MergedAnnotation<?> priorityAnnotation = annotations.get(JAVAX_PRIORITY_ANNOTATION); if (priorityAnnotation.isPresent()) { return priorityAnnotation.getInt(MergedAnnotation.VALUE); } return null; }
demo
public class AnnotationAwareOrderComparatorTests { @Test void sortInstancesWithSubclass() { List<Object> list = new ArrayList<>(); list.add(new B()); list.add(new C()); AnnotationAwareOrderComparator.sort(list); assertThat(list.get(0) instanceof C).isTrue(); assertThat(list.get(1) instanceof B).isTrue(); } @Test void sortInstancesWithOrderAndPriority() { List<Object> list = new ArrayList<>(); list.add(new B()); list.add(new A2()); AnnotationAwareOrderComparator.sort(list); assertThat(list.get(0) instanceof A2).isTrue(); assertThat(list.get(1) instanceof B).isTrue(); } @Order(1) private static class A { } @Order(2) private static class B { } private static class C extends A { } @Priority(1) private static class A2 { } }
小結(jié)
@Order與@Priority注解放置在類,接口或參數(shù)上,可以被繼承;它們之間是可以互相替換的關(guān)系。
spring源碼中有很多地方都顯式的調(diào)用AnnotationAwareOrderComparator的sort方法,也有一些地方調(diào)用的OrderComparator的sort方法,大家自己可以找找看。
我這里發(fā)現(xiàn)了一點(diǎn)有意思的地方,我們?nèi)绻x多個(gè)ControllerAdvice的bean,分別通過實(shí)現(xiàn)Ordered,PriorityOrdered接口來定義執(zhí)行時(shí)的順序,會發(fā)現(xiàn)上面我們總結(jié)的 PriorityOrdered優(yōu)先級就是比Ordered高 這一點(diǎn)不成立,其實(shí)只是spring將ControllerAdvice相關(guān)信息封裝了一下欺騙了我們。我看的源碼的版本是5.3.1,低于5.2版本的不會發(fā)生這樣的事情。這里我們就來看看5.2版本前后源碼有哪些變化,導(dǎo)致了這個(gè)現(xiàn)象的發(fā)生。
這里就拿RequestMappingHandlerAdapter初始化去尋找ControllerAdvice注解的代碼來舉例
private void initControllerAdviceCache() { if (getApplicationContext() == null) { return; } List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext()); // 5.2版本前使用下面注釋的這行代碼,5.2之后這行代碼就去掉了,而是在上面findAnnotatedBeans // 方法中使用OrderComparator.sort(adviceBeans) //AnnotationAwareOrderComparator.sort(adviceBeans); ... }
我們知道OrderComparator適用范圍是比AnnotationAwareOrderComparator要窄一點(diǎn)的,它不支持注解,那么上面這樣的改動是不是就意味著我們定義ControllerAdvice時(shí),就不能使用@Order與@Pri-ority呢?
其實(shí)它是支持的,ControllerAdviceBean#findAnnotatedBeans方法中會將我們定義的Con-trollerAdvice類包裝成ControllerAdviceBean,而ControllerAdviceBean是實(shí)現(xiàn)了Ordered接口的,那么OrderComparator#sort方法要想支持使用注解,ControllerAdviceBean的getOrder方法中就必須干點(diǎn)啥,分析了挺多,我們還是看源碼實(shí)現(xiàn)吧。
// 5.2版本后 public int getOrder() { if (this.order == null) { String beanName = null; Object resolvedBean = null; // 這里根據(jù)beanName獲取bean if (this.beanFactory != null && this.beanOrName instanceof String) { beanName = (String) this.beanOrName; String targetBeanName = ScopedProxyUtils.getTargetBeanName(beanName); boolean isScopedProxy = this.beanFactory.containsBean(targetBeanName); if (!isScopedProxy && !ScopedProxyUtils.isScopedTarget(beanName)) { resolvedBean = resolveBean(); } }else { resolvedBean = resolveBean(); } // 這里只判斷了是否實(shí)現(xiàn)了Ordered接口,并沒有對實(shí)現(xiàn)PriorityOrdered作特殊處理 // 這里優(yōu)先判斷是否實(shí)現(xiàn)了Ordered接口,如果同時(shí)使用注解的話將被忽略 if (resolvedBean instanceof Ordered) { this.order = ((Ordered) resolvedBean).getOrder(); }else { if (beanName != null && this.beanFactory instanceof ConfigurableBeanFactory) { ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) this.beanFactory; try { BeanDefinition bd = cbf.getMergedBeanDefinition(beanName); if (bd instanceof RootBeanDefinition) { Method factoryMethod = ((RootBeanDefinition) bd).getResolvedFactoryMethod(); if (factoryMethod != null) { // 這里將會從注解@Order與@Priority中獲取order值 this.order = OrderUtils.getOrder(factoryMethod); } } }catch (NoSuchBeanDefinitionException ex) { // ignore -> probably a manually registered singleton } } if (this.order == null) { if (this.beanType != null) { this.order = OrderUtils.getOrder(this.beanType, Ordered.LOWEST_PRECEDENCE); } else { this.order = Ordered.LOWEST_PRECEDENCE; } } } } return this.order; }
源碼分析后,我們來看一段測試demo
public class ControllerAdviceBeanTests { @ControllerAdvice @Order(100) @Priority(200) static class OrderedControllerAdvice implements Ordered { @Override public int getOrder() { return 42; } } @ControllerAdvice // Order和@Priority由于Order的實(shí)現(xiàn)應(yīng)該被忽略 @Order(100) @Priority(200) static class PriorityOrderedControllerAdvice implements PriorityOrdered { @Override public int getOrder() { return 55; } } @Configuration(proxyBeanMethods = false) static class Config { @Bean OrderedControllerAdvice orderedControllerAdvice() { return new OrderedControllerAdvice(); } @Bean PriorityOrderedControllerAdvice priorityOrderedControllerAdvice() { return new PriorityOrderedControllerAdvice(); } } @Test @SuppressWarnings({"rawtypes", "unchecked"}) public void findAnnotatedBeansSortsBeans() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class); List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(context); // 輸出順序并不是 55 42,而是42,55 for (ControllerAdviceBean adviceBean : adviceBeans) { System.out.println (adviceBean.getOrder ()); } } }
關(guān)于“怎么用Spring中的@Order進(jìn)行排序”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識,可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會為大家更新不同的知識點(diǎn)。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。