<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
很長一段時間沒有寫部落格了,今天一時心血來潮,突然寫出這篇文章就很突兀。但是看到網上關於Spring的@Order註解的不是特別準確的結論,想著還是表達一下看法,當然也是通過寫文章來讓自己的思路更清晰一點,如果有不是很贊同的部分,希望可以一起討論。
首先先說結論:Spring的@Order註解(或者實現Ordered介面、或者實現PriorityOrdered介面),不決定Bean的範例化順序和執行順序,更不會影響Spring的Bean的掃描順序;它影響著Spring將掃描的多個Bean放入陣列、集合(Map)時的排序。
下面我只驗證@Order註解,至於實現介面的方式有興趣的可以試一下。
@Slf4j(topic = "e") @Order(1) @Component public class OrderTestService1 { public OrderTestService1(){ log.debug("order-{}",this.getClass().getAnnotation(Order.class).value()); } } @Slf4j(topic = "e") @Order(2) @Component public class OrderTestService2 { public OrderTestService2(){ log.debug("order-{}",this.getClass().getAnnotation(Order.class).value()); } } @Slf4j(topic = "e") @Order(3) @Component public class OrderTestService3 { public OrderTestService3(){ log.debug("order-{}",this.getClass().getAnnotation(Order.class).value()); } }
列印順序如下:
OrderTestService1.java 行數=13 10:56:20.756 [main] DEBUG e - order-1
OrderTestService2.java 行數=13 10:56:20.760 [main] DEBUG e - order-2
OrderTestService3.java 行數=13 10:56:20.761 [main] DEBUG e - order-3
改變OrderTestService三個類的註解序值
@Slf4j(topic = "e") @Order(3) @Component public class OrderTestService1 { public OrderTestService1(){ log.debug("order-{}",this.getClass().getAnnotation(Order.class).value()); } } @Slf4j(topic = "e") @Order(2) @Component public class OrderTestService2 { public OrderTestService2(){ log.debug("order-{}",this.getClass().getAnnotation(Order.class).value()); } } @Slf4j(topic = "e") @Order(1) @Component public class OrderTestService3 { public OrderTestService3(){ log.debug("order-{}",this.getClass().getAnnotation(Order.class).value()); } }
結果:當改變OrderTestService介面的三個類註解序值時,類的範例化順序根本沒有變化,即@Order註解不決定Bean的範例化順序。
@Slf4j(topic = "e") public class E { public void orderList(){ int orderValue = 0; if(this.getClass().isAnnotationPresent(Order.class)){ Order order = this.getClass().getAnnotation(Order.class); orderValue = order.value(); } log.debug("List Order postProcessBeanFactory {} order={}",this.getClass().getSimpleName(),orderValue); } } @Slf4j(topic = "e") @Order(3) @Component public class OrderTestService1 extends E{ public OrderTestService1(){ log.debug("order-{}",this.getClass().getAnnotation(Order.class).value()); } } @Slf4j(topic = "e") @Order(2) @Component public class OrderTestService2 extends E{ public OrderTestService2(){ log.debug("order-{}",this.getClass().getAnnotation(Order.class).value()); } } @Slf4j(topic = "e") @Order(1) @Component public class OrderTestService3 extends E{ public OrderTestService3(){ log.debug("order-{}",this.getClass().getAnnotation(Order.class).value()); } } @Component public class OrderTestService { List<E> beanFactoryPostProcessor; public List<E> getBeanFactoryPostProcessor() { return beanFactoryPostProcessor; } @Autowired public void setBeanFactoryPostProcessor(List<E> beanFactoryPostProcessor) { this.beanFactoryPostProcessor = beanFactoryPostProcessor; } }
列印順序如下:
E.java 行數=15 11:01:47.756 [main] DEBUG e - List Order postProcessBeanFactory OrderTestService3 order=1
E.java 行數=15 11:01:47.756 [main] DEBUG e - List Order postProcessBeanFactory OrderTestService2 order=2
E.java 行數=15 11:01:47.756 [main] DEBUG e - List Order postProcessBeanFactory OrderTestService1 order=3
結論:當通過注入型別為集合或者陣列(可以自行認證)時,@Order的註解值影響注入的順序,而這並不代表著說@Order註解影響著Bean的執行順序,接著往下看。
不影響Bean的執行順序
然上面的三個類全都實現BeanFactoryPostProcessor,然後觀察postProcessBeanFactory方法的執行順序,如下:
@Slf4j(topic = "e") @Order(3) @Component public class OrderTestService1 extends E implements BeanFactoryPostProcessor { public OrderTestService1(){ log.debug("order-{}",this.getClass().getAnnotation(Order.class).value()); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { int orderValue = 0; if(this.getClass().isAnnotationPresent(Order.class)){ Order order = this.getClass().getAnnotation(Order.class); orderValue = order.value(); } log.debug("execute postProcessBeanFactory a order={}",orderValue); } } @Slf4j(topic = "e") @Order(2) @Component public class OrderTestService2 extends E implements BeanFactoryPostProcessor { public OrderTestService2(){ log.debug("order-{}",this.getClass().getAnnotation(Order.class).value()); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { int orderValue = 0; if(this.getClass().isAnnotationPresent(Order.class)){ Order order = this.getClass().getAnnotation(Order.class); orderValue = order.value(); } log.debug("execute postProcessBeanFactory a order={}",orderValue); } } @Slf4j(topic = "e") @Order(1) @Component public class OrderTestService3 extends E implements BeanFactoryPostProcessor { public OrderTestService3(){ log.debug("order-{}",this.getClass().getAnnotation(Order.class).value()); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { int orderValue = 0; if(this.getClass().isAnnotationPresent(Order.class)){ Order order = this.getClass().getAnnotation(Order.class); orderValue = order.value(); } log.debug("execute postProcessBeanFactory a order={}",orderValue); } }
結論:通過上面的列印結果,Spring的@Order註解並不影響Bean的執行順序。
接下來主要分析為什麼@Order註解在注入型別為集合時可以影響其順序。
原始碼位置:org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency方法中這一段
@Nullable public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor); try { Object shortcut = descriptor.resolveShortcut(this); if (shortcut != null) { return shortcut; } // 獲取依賴的型別 Class<?> type = descriptor.getDependencyType(); Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor); if (value != null) { if (value instanceof String) { String strVal = resolveEmbeddedValue((String) value); BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null); value = evaluateBeanDefinitionString(strVal, bd); } TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); try { return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor()); } catch (UnsupportedOperationException ex) { // A custom TypeConverter which does not support TypeDescriptor resolution... return (descriptor.getField() != null ? converter.convertIfNecessary(value, type, descriptor.getField()) : converter.convertIfNecessary(value, type, descriptor.getMethodParameter())); } } // resolveMultipleBeans方法是解析當前依賴項是否支援多個bean注入 比如list // 如果是能支援多個注入則在該方法內部就完成了bean的查詢,否則下面完成查詢 Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter); if (multipleBeans != null) { return multipleBeans; } // 完成查詢的功能,有可能會查詢出來多個結果 // 需要注意的是這裡的多個結果和上面的支援的多個注入不是同一回事 Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); if (matchingBeans.isEmpty()) { // 如果沒有找到而且你又在依賴上面加上了必須的條件,則會出異常 if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } // 如果沒有加必須條件則返回null,意思就是不注入任何物件 return null; } String autowiredBeanName; Object instanceCandidate; // 假設找出來多個 if (matchingBeans.size() > 1) { // 通過descriptor 也就是依賴描述器來推斷出來需要注入的這個物件的名字 // 注意這裡不是當前注入物件的名字而是需要注入的物件的名字 // 假設A依賴B,這裡推斷的B這個物件應該叫什麼名字 autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor); // 假設推斷出來為null // 什麼情況下為null?就是你提供的名字和任何找出來的物件的名字匹配不上 if (autowiredBeanName == null) { if (isRequired(descriptor) || !indicatesMultipleBeans(type)) { return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans); } else { // In case of an optional Collection/Map, silently ignore a non-unique case: // possibly it was meant to be an empty collection of multiple regular beans // (before 4.3 in particular when we didn't even look for collection beans). return null; } } // 獲取類 通過名字 instanceCandidate = matchingBeans.get(autowiredBeanName); } else { // We have exactly one match. Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next(); autowiredBeanName = entry.getKey(); instanceCandidate = entry.getValue(); } if (autowiredBeanNames != null) { autowiredBeanNames.add(autowiredBeanName); } if (instanceCandidate instanceof Class) { instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this); } Object result = instanceCandidate; if (result instanceof NullBean) { if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } result = null; } if (!ClassUtils.isAssignableValue(type, result)) { throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass()); } return result; } finally { ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint); } }
主要看這一句:Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
@Nullable private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) { Class<?> type = descriptor.getDependencyType(); if (descriptor instanceof StreamDependencyDescriptor) { // findAutowireCandidates 根據型別查詢 Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); if (autowiredBeanNames != null) { autowiredBeanNames.addAll(matchingBeans.keySet()); } Stream<Object> stream = matchingBeans.keySet().stream() .map(name -> descriptor.resolveCandidate(name, type, this)) .filter(bean -> !(bean instanceof NullBean)); if (((StreamDependencyDescriptor) descriptor).isOrdered()) { stream = stream.sorted(adaptOrderComparator(matchingBeans)); } return stream; } else if (type.isArray()) { Class<?> componentType = type.getComponentType(); ResolvableType resolvableType = descriptor.getResolvableType(); Class<?> resolvedArrayType = resolvableType.resolve(type); if (resolvedArrayType != type) { componentType = resolvableType.getComponentType().resolve(); } if (componentType == null) { return null; } // findAutowireCandidates 根據型別查詢 Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType, new MultiElementDescriptor(descriptor)); if (matchingBeans.isEmpty()) { return null; } if (autowiredBeanNames != null) { autowiredBeanNames.addAll(matchingBeans.keySet()); } TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); Object result = converter.convertIfNecessary(matchingBeans.values(), resolvedArrayType); if (result instanceof Object[]) { Comparator<Object> comparator = adaptDependencyComparator(matchingBeans); if (comparator != null) { Arrays.sort((Object[]) result, comparator); } } return result; } else if (Collection.class.isAssignableFrom(type) && type.isInterface()) { Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric(); if (elementType == null) { return null; } // findAutowireCandidates 根據型別查詢 Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType, new MultiElementDescriptor(descriptor)); if (matchingBeans.isEmpty()) { return null; } if (autowiredBeanNames != null) { autowiredBeanNames.addAll(matchingBeans.keySet()); } TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); Object result = converter.convertIfNecessary(matchingBeans.values(), type); if (result instanceof List) { if (((List<?>) result).size() > 1) { Comparator<Object> comparator = adaptDependencyComparator(matchingBeans); if (comparator != null) { ((List<?>) result).sort(comparator); } } } return result; } else if (Map.class == type) { ResolvableType mapType = descriptor.getResolvableType().asMap(); Class<?> keyType = mapType.resolveGeneric(0); if (String.class != keyType) { return null; } Class<?> valueType = mapType.resolveGeneric(1); if (valueType == null) { return null; } // findAutowireCandidates 根據型別查詢 Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, new MultiElementDescriptor(descriptor)); if (matchingBeans.isEmpty()) { return null; } if (autowiredBeanNames != null) { autowiredBeanNames.addAll(matchingBeans.keySet()); } return matchingBeans; } else { return null; } }
主要看這一段:
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) { Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric(); if (elementType == null) { return null; } // findAutowireCandidates 根據型別查詢 Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType, new MultiElementDescriptor(descriptor)); if (matchingBeans.isEmpty()) { return null; } if (autowiredBeanNames != null) { autowiredBeanNames.addAll(matchingBeans.keySet()); } TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); Object result = converter.convertIfNecessary(matchingBeans.values(), type); if (result instanceof List) { if (((List<?>) result).size() > 1) { // 呼叫比較器 Comparator<Object> comparator = adaptDependencyComparator(matchingBeans); if (comparator != null) { ((List<?>) result).sort(comparator); } } } return result; }
@Nullable private Comparator<Object> adaptDependencyComparator(Map<String, ?> matchingBeans) { // 獲取比較器 Comparator<Object> comparator = getDependencyComparator(); if (comparator instanceof OrderComparator) { return ((OrderComparator) comparator).withSourceProvider( createFactoryAwareOrderSourceProvider(matchingBeans)); } else { return comparator; } } public Comparator<Object> withSourceProvider(OrderSourceProvider sourceProvider) { return (o1, o2) -> doCompare(o1, o2, sourceProvider); } private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderSourceProvider sourceProvider) { // 是否實現了PriorityOrdered介面 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); }
接下來比較重要,上面註釋了是否實現了PriorityOrdered介面,如果沒有則呼叫getOrder方法,getOrder方法判斷是否實現了Order介面,如果沒有獲取@Order註解值。
private int getOrder(@Nullable Object obj, @Nullable OrderSourceProvider sourceProvider) { Integer order = null; if (obj != null && sourceProvider != null) { // 拿到實現了Order介面的類 Object orderSource = sourceProvider.getOrderSource(obj); if (orderSource != null) { if (orderSource.getClass().isArray()) { for (Object source : ObjectUtils.toObjectArray(orderSource)) { order = findOrder(source); if (order != null) { break; } } } else { order = findOrder(orderSource); } } } return (order != null ? order : getOrder(obj)); } protected int getOrder(@Nullable Object obj) { if (obj != null) { Integer order = findOrder(obj); if (order != null) { return order; } } return Ordered.LOWEST_PRECEDENCE; } @Override @Nullable protected Integer findOrder(Object obj) { Integer order = super.findOrder(obj); if (order != null) { return order; } return findOrderFromAnnotation(obj); } @Nullable private Integer findOrderFromAnnotation(Object obj) { AnnotatedElement element = (obj instanceof AnnotatedElement ? (AnnotatedElement) obj : obj.getClass()); MergedAnnotations annotations = MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY); Integer order = OrderUtils.getOrderFromAnnotations(element, annotations); if (order == null && obj instanceof DecoratingProxy) { return findOrderFromAnnotation(((DecoratingProxy) obj).getDecoratedClass()); } return order; }
總結下來就是:當我們通過建構函式或者set方法注入進某個List<類>時,Spring的DefaultListableBeanFactory類會在注入時獲取AnnotationAwareOrderComparator比較器幫助我們對類進行排序,AnnotationAwareOrderComparator是OrderComparator的子類,而OrderComparator實現了比較器Comparator介面。排序的策略會先判斷是否實現PriorityOrdered介面,如果沒有接著會判斷是否實現Order介面,此時也沒有就會根據註解值進行比較。
到此這篇關於Spring @Order註解使用詳解的文章就介紹到這了,更多相關Spring @Order 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援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