Spring@Order注解使用详解

Spring@Order注解使用详解

目录

前言

例子一

例子二

例子三

实例论证

源码分析

前言

很长一段时间没有写博客了,今天一时心血来潮,突然写出这篇文章就很突兀。但是看到网上关于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 内容请搜索易知道(ezd.cc)以前的文章或继续浏览下面的相关文章希望大家以后多多支持易知道(ezd.cc)!

推荐阅读

    01- 第一天 spring boot2.3.1 +vue3.0 后台管理系统的研发

    01- 第一天 spring boot2.3.1 +vue3.0 后台管理系统的研发,自己的,后台,后台框架一直想开发一套完全属于自己的后台,但是18年的时候,曾经答

    1.springCloud学习-注册中心eureka

    1.springCloud学习-注册中心eureka,中心,注册表,1.背景 接下来我们学习SpringCloud的注册中心,作为微服务的第一的专题,我们需要将服务注册

    Spring和SpringMVC的区别是什么

    Spring和SpringMVC的区别是什么,框架,项目,本文目录Spring和SpringMVC的区别是什么springboot 和spring的区别java编程语言中,spring boot

    SpringBoot自动配置的实现原理是什么

    SpringBoot自动配置的实现原理是什么,配置,组件,文件,方法,注册,获取,一、什么是springboot自动配置SpringBoot通过@EnableAutoConfiguration注

    SpringBoot启动流程是什么

    SpringBoot启动流程是什么,应用程序,方法,组件,上下文,对象,配置,SpringBoot启动过程简介SpringBoot应用程序的启动过程可以分为以下几个步骤:加

    disorder 是什么意思

    disorder 是什么意思,命令,订单,disorder 是什么意思1. n。混乱;凌乱;不舒服;失衡;疾病2. VT。破坏1.发音:英国。2.用法:1、动词+~  check a