我的库必须处理以任意顺序指定的多个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实例,因此在类级别上既未实现订单也未具有订单注释。我必须启用BeanPostProcessor或配置选项吗?
如何告诉spring保留带注释的顺序或使用应用程序上下文的bean定义对bean进行适当排序?
答案 0 :(得分:0)
要使测试用例正常工作,您需要使用Ordered
界面而不是注释。
让我们检查AnnotationAwareOrderComparator的源代码。请注意,您是将对象直接传递给sort方法。 AnnotationAwareOrderComparator在粘贴的对象上使用findOrder
,以查找三个工件@Priority
注释@Order
注释或@Ordered
界面之一。在您的情况下,您正在传递拦截器实例,因此对Methidf和Class的if检查将返回false。您将遇到最后一个if方法:if (obj != null)
在这种情况下,它将只检查您的对象@@注解,在您的情况下为null。实际上,您的测试用例是错误的。但是请注意,如果实现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;
}