java - 按方法级别@Order注释对spring @Beans进行排序
问题描述
我的库必须处理以任意顺序指定的多个 bean(拦截器)(因为它们分布在多个配置文件中)。在我可以应用它们之前,我必须按它们的优先级对它们进行排序。我用AnnotationAwareOrderComparator.sort(beans)
它。只要在@Order
该拦截器的类级别上添加注释,这就会很好地工作。但是当我尝试在 @Bean 方法的 @Configuration 类中使用它时它不起作用:
@Configuration
public class Config {
@Bean
@Order(1)
public ServerInterceptor exceptionTranslatingServerInterceptor() {
return ...;
}
@Bean
@Order(2)
public ServerInterceptor authenticatingServerInterceptor() {
return ...;
}
@Bean
@Order(3)
public ServerInterceptor authorizationCheckingServerInterceptor() {
return ...
}
}
但是,如果我添加这样的测试:
@Test
void testOrderingOfTheDefaultInterceptors() {
List<ServerInterceptor> expected = new ArrayList<>();
expected.add(applicationContext.getBean(ExceptionTranslatingServerInterceptor.class));
expected.add(applicationContext.getBean(AuthenticatingServerInterceptor.class));
expected.add(applicationContext.getBean(AuthorizationCheckingServerInterceptor.class));
List<ServerInterceptor> actual = new ArrayList<>(this.registry.getServerInterceptors());
assertEquals(expected, actual); // Accidentally passes
// System.out.println(actual);
Collections.shuffle(actual);
AnnotationAwareOrderComparator.sort(actual);
assertEquals(expected, actual); // Fails
// System.out.println(actual);
}
然后测试将失败。从我的调试中我知道AnnotationAwareOrderComparator.findOrder(Object)
对于这些 bean 的顺序总是返回 null (未指定)。可能是因为 bean 实例没有被代理,因此在它们的类级别上既没有实现 order 也没有 order 注释。是否有我必须启用的 BeanPostProcessor 或配置选项?
如何告诉 spring 保留带注释的顺序或使用应用程序上下文的 bean 定义对 bean 进行适当的排序?
解决方案
为了使您的测试用例正常工作,您需要使用Ordered
接口而不是注释。让我们检查一下 AnnotationAwareOrderComparator 的源代码。请注意,您将对象直接传递给 sort 方法。AnnotationAwareOrderComparator 使用findOrder
传递的对象来查找三个工件@Priority
注释@Order
注释或@Ordered
接口之一。在您的情况下,您正在传递拦截器实例,因此 if 检查 Methidf 和 Class 将返回 false。您将点击最后一个 if 方法:if (obj != null)
在这种情况下,它只会检查你的 @Order 注释的对象类,在你的情况下这将是空的。实际上,您的测试用例是错误的。请注意,如果您实现 Ordered 接口,您的测试用例将按预期运行。
public static void sort(List list) {
if (list.size() > 1) {
Collections.sort(list, INSTANCE);
}
}
protected Integer findOrder(Object obj) {
// Check for regular Ordered interface
Integer order = super.findOrder(obj);
if (order != null) {
return order;
}
// Check for @Order and @Priority on various kinds of elements
if (obj instanceof Class) {
return OrderUtils.getOrder((Class) obj);
}
else if (obj instanceof Method) {
Order ann = AnnotationUtils.findAnnotation((Method) obj, Order.class);
if (ann != null) {
return ann.value();
}
}
else if (obj instanceof AnnotatedElement) {
Order ann = AnnotationUtils.getAnnotation((AnnotatedElement) obj, Order.class);
if (ann != null) {
return ann.value();
}
}
else if (obj != null) {
return OrderUtils.getOrder(obj.getClass());
}
return null;
}
推荐阅读
- r - 使用 stat_ellipse ggplot2 时删除某些组的置信椭圆
- scala - AWS EMR 上的 Spark:java.lang.NoSuchMethodError: scala.Product.$init$(Lscala/Product;)V
- javascript - 单击表格单元格时选中复选框
- javascript - 在桌面上我的网站上打开新链接时,它会在 Chrome 上加载移动 CSS
- python - 在 Windows 中安装 steup 轮时面临“NewConnectionError”
- javascript - 移除事件监听器
- javascript - 如何将长字符串转换为对象列表
- http - 在 Google Stackdriver 中监控传入的 Kubernetes HTTP 请求
- php - “代码生成器”中相同数字的问题
- html - Web 项目未部署