按方法级别@Order注释对spring @Beans进行排序

ST-*_*DDT 5 java sorting configuration spring

我的库必须处理以任意顺序指定的多个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 ...
    }

}
Run Code Online (Sandbox Code Playgroud)

但是,如果我添加这样的测试:

@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);
}
Run Code Online (Sandbox Code Playgroud)

然后测试将失败。通过调试,我知道AnnotationAwareOrderComparator.findOrder(Object)对于这些bean的顺序总是返回null(未指定)。可能是因为未实例化Bean实例,因此在类级别上既未实现订单也未具有订单注释。我必须启用BeanPostProcessor或配置选项吗?

控制流

如何告诉spring保留带注释的顺序或使用应用程序上下文的bean定义对bean进行适当排序?

Ale*_*rov 1

为了使您的测试用例正常工作,您需要使用Ordered接口而不是注释。让我们检查一下 AnnotationAwareOrderComparator 的源代码。请注意,您直接将对象传递给排序方法。AnnotationAwareOrderComparator 使用findOrder所传递的对象来查找三个工件@Priority注释@Order注释或@Ordered接口之一。在您的情况下,您正在传递拦截器实例,因此对 Methidf 和 Class 的 if 检查将返回 false。您将点击最后一个 if 方法:if (obj != null)

在这种情况下,它只会检查您的对象类中的 @Order 注释,在您的情况下,该注释将为 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;
    }
Run Code Online (Sandbox Code Playgroud)