尧图精选

Spring OrderUtils 源码解析:从注解缓存到排序优先级提取的完整机制

🕒 发布时间:2026/9/13 2:53:52 📁 来源:尧图网络
Spring OrderUtils 源码解析从注解缓存到排序优先级提取的完整机制【免费下载链接】source-code-hunter 从源码层面剖析挖掘互联网行业主流技术的底层实现原理为广大开发者 “提升技术深度” 提供便利。目前开放 Spring 全家桶Mybatis、Netty、Dubbo 框架及 Redis、Tomcat 中间件等项目地址: https://gitcode.com/GitHub_Trending/so/source-code-hunter导读OrderUtils是 Spring 框架org.springframework.core.annotation包下的排序核心工具类它负责从类上解析Order注解与Priorityjavax.annotation.Priority注解从而得到用于排序的整型优先级值。本文以仓库文档 Spring-OrderUtils.md 为主体结合 Spring-AnnotationUtils.md、Spring-OrderComparator.md 及 IoC 容器中 BeanPostProcessor.md、Spring-Conditional.md 等实际应用场景逐行剖析getOrder、getPriority两个方法的实现细节与缓存设计帮助你理解 Spring 中谁先执行、谁后执行这一排序体系的最底层数据来源。一、OrderUtils 类概览OrderUtils是 Spring 排序体系中的注解读取层。它的职责非常聚焦getOrder(Class? type)从目标类上寻找Order注解返回其value值getPriority(Class? type)从目标类上寻找Priority注解javax.annotation.Priority返回其value值两者均内置了基于ConcurrentHashMap的缓存orderCache与priorityCache避免对同一类型反复进行昂贵的注解反射查找。与之配套的排序比较层则是OrderComparator见 Spring-OrderComparator.md它通过getOrder/findOrder拿到每个元素的 order 值后用Integer.compare(i1, i2)完成最终比较。而AnnotationAwareOrderComparator则在OrderComparator基础上叠加了OrderUtils的类级注解解析能力被广泛用于 Spring 各模块的排序入口例如 Spring-Conditional.md 中的AnnotationAwareOrderComparator.sort(conditions)、Spring-SpringFactoriesLoader.md 中的AnnotationAwareOrderComparator.sort(result)。因此OrderUtils是整个排序链条的源头先由它从注解中提取数值再由比较器依据数值确定先后次序。二、getOrder查找 Order 注解并返回优先级getOrder(Class? type)的源码对应原文档第一个代码块如下Nullable public static Integer getOrder(Class? type) { // 缓存中获取 Object cached orderCache.get(type); if (cached ! null) { // 返回 int return (cached instanceof Integer ? (Integer) cached : null); } /** * 注解工具类,寻找{link Order}注解 */ Order order AnnotationUtils.findAnnotation(type, Order.class); Integer result; if (order ! null) { // 返回 result order.value(); } else { result getPriority(type); } // key: 类名,value: intValue orderCache.put(type, (result ! null ? result : NOT_ANNOTATED)); return result; }该方法的执行流程分为四步查缓存以Class为 key 从orderCache取缓存值。若命中判断缓存值是否为Integer实例是则直接返回否则返回null表示该类型此前已判定为无注解。找注解调用AnnotationUtils.findAnnotation(type, Order.class)查找Order注解。注意这里使用的是findAnnotation而非getAnnotation这意味着它不仅支持直接标注还支持元注解meta-annotation与层级查找。降级处理若Order不存在则回退调用getPriority(type)即尝试读取javax.annotation.Priority注解——这保证了同时兼容 Spring 体系与 Java 标准Priority注解的排序语义。写缓存将结果写入orderCache。无注解时存入哨兵值NOT_ANNOTATED避免每次调用都重复执行昂贵的注解扫描。关于findAnnotation的底层逻辑可以参考仓库中 Spring-AnnotationUtils.md 的对应分析其核心私有方法会先在目标元素上执行getDeclaredAnnotation若未命中则遍历该元素上声明的所有注解递归检查它们是否携带目标注解元注解机制并利用visited集合防止循环引用private static A extends Annotation A findAnnotation( AnnotatedElement annotatedElement, ClassA annotationType, SetAnnotation visited) { // 直接获取注解 A annotation annotatedElement.getDeclaredAnnotation(annotationType); if (annotation ! null) { return annotation; } // 多级注解 for (Annotation declaredAnn : getDeclaredAnnotations(annotatedElement)) { Class? extends Annotation declaredType declaredAnn.annotationType(); // 注解是否由 java.lang.annotation 提供 if (!isInJavaLangAnnotationPackage(declaredType) visited.add(declaredAnn)) { annotation findAnnotation((AnnotatedElement) declaredType, annotationType, visited); if (annotation ! null) { return annotation; } } } return null; }这也解释了getOrder中NOT_ANNOTATED哨兵缓存存在的重要意义元注解递归查找的代价比普通反射大得多缓存可以显著降低排序过程中对同一类重复调用时的开销。三、getPriority读取 javax.annotation.Priority 注解getPriority(Class? type)的源码对应原文档第二个代码块如下Nullable public static Integer getPriority(Class? type) { if (priorityAnnotationType null) { return null; } // 缓存中获取 Object cached priorityCache.get(type); if (cached ! null) { // 不为空返回 return (cached instanceof Integer ? (Integer) cached : null); } // 注解工具获取注解 Annotation priority AnnotationUtils.findAnnotation(type, priorityAnnotationType); Integer result null; if (priority ! null) { // 获取 value result (Integer) AnnotationUtils.getValue(priority); } // 向缓存插入数据 priorityCache.put(type, (result ! null ? result : NOT_ANNOTATED)); return result; }这段代码有几个值得注意的细节priorityAnnotationType可能为空该静态字段保存的是javax.annotation.Priority的Class对象通过ClassUtils.isPresent之类的检测按需加载。当运行环境如 JDK 精简镜像中不存在javax.annotation包时该字段为null方法直接返回null保证框架在缺少该依赖时依然可用。读取 value 的方式不同这里没有像Order那样直接调用order.value()而是通过AnnotationUtils.getValue(priority)反射获取名为value的属性。getValue的底层实现见 Spring-AnnotationUtils.md本质上是public static Object getValue(Nullable Annotation annotation, Nullable String attributeName) { if (annotation null || !StringUtils.hasText(attributeName)) { return null; } try { // 根据 attributeName 获取注解对应函数 Method method annotation.annotationType().getDeclaredMethod(attributeName); ReflectionUtils.makeAccessible(method); // 反射执行方法 return method.invoke(annotation); } catch (NoSuchMethodException ex) { return null; } catch (InvocationTargetException ex) { rethrowAnnotationConfigurationException(ex.getTargetException()); throw new IllegalStateException(Could not obtain value for annotation attribute attributeName in annotation, ex); } catch (Throwable ex) { handleIntrospectionFailure(annotation.getClass(), ex); return null; } }即通过annotation.annotationType().getDeclaredMethod(value)定位注解属性方法再经ReflectionUtils.makeAccessible与method.invoke反射取值。之所以采用反射而非强类型访问是因为javax.annotation.Priority并非 Spring 自身定义的注解无法在编译期直接绑定反射是唯一的通用读取方式。 3.独立的priorityCache与orderCache分开缓存二者互不干扰同样使用NOT_ANNOTATED哨兵值标记未标注状态。四、缓存与哨兵值NOT_ANNOTATED 的设计意图两个方法在缓存写入时都用到了NOT_ANNOTATED哨兵值private static final Object NOT_ANNOTATED new Object();其作用是当某类型没有标注任何相关注解时缓存中存入一个非 Integer 的对象作为占位。下次查询时Object cached orderCache.get(type); if (cached ! null) { return (cached instanceof Integer ? (Integer) cached : null); }通过cached instanceof Integer判断即可区分两种情况缓存值能强转为Integer说明该类型有注解返回真实 order 值缓存值是NOT_ANNOTATED说明该类型无注解返回null。若直接缓存null值则需要额外的手段区分未缓存与已缓存但无注解两种状态例如containsKey判断哨兵值让逻辑更加清晰也使得ConcurrentHashMap的get一次调用即可完成判断。这种哨兵缓存模式在 Spring 源码中非常常见本质上是用空间换时间的典型应用。五、与 OrderComparator / AnnotationAwareOrderComparator 的协作单独看OrderUtils并不产生排序行为真正的排序发生在比较器层。仓库文档 Spring-OrderComparator.md 展示了OrderComparator.doCompare的核心逻辑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); // 对比两个 Order 值得大小返回 return Integer.compare(i1, i2); }排序规则非常明确实现了PriorityOrdered接口的对象永远排在未实现该接口的对象之前其余对象按getOrder提取到的整数值通过Integer.compare(i1, i2)升序排列Integer.compare中order 值越小优先级越高与Ordered.HIGHEST_PRECEDENCEInteger.MIN_VALUE、Ordered.LOWEST_PRECEDENCEInteger.MAX_VALUE的定义保持一致。在OrderComparator的getOrder内部会通过findOrder先判断对象是否实现Ordered接口Nullable protected Integer findOrder(Object obj) { // 获取 Ordered 实现类 return (obj instanceof Ordered ? ((Ordered) obj).getOrder() : null); }而AnnotationAwareOrderComparator重写了findOrder当对象不是Ordered实现时进一步调用OrderUtils.getOrder(obj.getClass())从类注解上解析 order 值。两张调试截图清晰地呈现了这一协作过程image-20200116141838601.png展示了getOrder方法处理来自OrderSourceProvider的数组型排序源包含两个StubOrdered实例order 分别为 10 与 -25验证了多排序源逐一提取的逻辑image-20200116141932486.png展示了for循环遍历排序源、调用findOrder(source)提取具体 order 值返回 10的调试现场。由此可见OrderUtils与比较器之间的关系是比较器负责如何比OrderUtils 负责比什么——后者为前者提供注解层面的数值来源二者共同构成 Spring 完整的排序机制。六、OrderUtils 在 Spring 容器中的实际应用场景理解了实现之后再来看它在 Spring 中的典型应用场景可以进一步加深认识。场景一BeanPostProcessor 的分组排序在 BeanPostProcessor.md 中registerBeanPostProcessors将容器中所有BeanPostProcessor分为三组实现PriorityOrdered的、实现Ordered的、两者都未实现的if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { priorityOrderedPostProcessors.add(pp); } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) { orderedPostProcessorNames.add(ppName); } else { nonOrderedPostProcessorNames.add(ppName); }执行顺序依次为PriorityOrdered→Ordered按getOrder()值排序→ 无排序接口的。这里的Ordered.getOrder()取值与注解解析后的 order 值在语义上完全一致均遵循数值越小越先执行的规则。场景二Condition 条件的求值排序在 Spring-Conditional.md 中ConfigurationCondition的求值前会先排序AnnotationAwareOrderComparator.sort(conditions);Condition本身并非Ordered实现此时正是AnnotationAwareOrderComparator通过OrderUtils.getOrder(condition.getClass())解析Order注解来获得排序依据。这也是OrderUtils在注解层面发挥作用的最直接案例。场景三HandlerMapping 的注册排序在 SpringMVC 的设计与实现 中AbstractHandlerMapping实现Ordered接口容器通过OrderComparator.sort(this.handlerMappings)依据 order 值确定多个HandlerMapping的优先级从而决定请求先由哪个映射器尝试匹配。七、小结OrderUtils虽然只有两个核心方法却是理解 Spring 排序体系的关键起点getOrder优先解析Order注解未命中时回退到PrioritygetPriority通过反射读取javax.annotation.Priority的 value且对缺失依赖做了空值保护双缓存 哨兵值orderCache、priorityCache配合NOT_ANNOTATED用空间换时间避免重复的元注解递归查找协作链路OrderUtils提取数值 →OrderComparator比较数值 → 容器BeanPostProcessor、Condition、HandlerMapping 等依据排序结果决定执行次序。通过本文的梳理当你再看到AnnotationAwareOrderComparator.sort(...)或PriorityOrdered分组逻辑时就能清晰地知道背后 order 值究竟从何而来、缓存机制如何兜底、以及与Order/Priority注解之间的完整映射关系。若希望进一步深入可继续阅读仓库中的 Spring-AnnotationUtils.md注解查找与取值底层、Spring-OrderComparator.md比较器实现以及 BeanPostProcessor.md容器内实际排序场景。【免费下载链接】source-code-hunter 从源码层面剖析挖掘互联网行业主流技术的底层实现原理为广大开发者 “提升技术深度” 提供便利。目前开放 Spring 全家桶Mybatis、Netty、Dubbo 框架及 Redis、Tomcat 中间件等项目地址: https://gitcode.com/GitHub_Trending/so/source-code-hunter创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →