对spring @Beans按方法级别排序@Order注解

juzqafwq  于 2023-01-12  发布在  Spring
关注(0)|答案(2)|浏览(134)

我的库必须处理多个bean(拦截器)以任意顺序指定的(因为它们分布在多个配置文件中)。在应用它们之前,我必须按照它们的优先级对它们进行排序。我使用AnnotationAwareOrderComparator.sort(beans)来实现这一点。只要@Order注解添加在拦截器的类级别上,它就可以很好地工作。但是当我尝试在@中使用它时,它就不起作用了@Bean方法上的配置类:

@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进行排序?

0g0grzrc

0g0grzrc1#

要使测试用例正常工作,您需要使用Ordered接口而不是注解。让我们检查AnnotationAwareOrderComparator的源代码。请注意,您是直接将对象传递给sort方法的。AnnotationAwareOrderComparator正在使用pased对象上的findOrder,以便查找三个工件@Priority注解@Order注解或@Ordered之一接口。在您的例子中,您正在传递拦截器示例,因此对Methidf和Class的if检查将返回false。您将命中最后一个if方法:if (obj != null)
在这种情况下,它只会检查对象类中@Order注解,在您的情况下,该注解将为null。2实际上,您的测试用例是错误的。3请注意,如果您实现了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;
    }
ykejflvf

ykejflvf2#

我找到了一种方法来访问仅出现在bean工厂方法中的注解:

public static Comparator<Object> beanFactoryAwareOrderComparator(final ApplicationContext context,
            final Class<?> beanType) {
        final Map<?, String> beans = HashBiMap.create(context.getBeansOfType(beanType)).inverse();
        return OrderComparator.INSTANCE.withSourceProvider(bean -> {

            // The AnnotationAwareOrderComparator does not have the "withSourceProvider" method
            // The OrderComparator.withSourceProvider does not properly account for the annotations
            final Integer priority = AnnotationAwareOrderComparator.INSTANCE.getPriority(bean);
            if (priority != null) {
                return (Ordered) () -> priority;
            }

            // Consult the bean factory method for annotations
            final String beanName = beans.get(bean);
            if (beanName != null) {
                final Order order = context.findAnnotationOnBean(beanName, Order.class);
                if (order != null) {
                    return (Ordered) order::value;
                }
            }

            // Nothing present
            return null;
        });
    }

来源:易东楠/grpc-spring-boot-starter/拦截器订单

相关问题