Сортировка spring @Beans по уровню метода аннотации @Order

Моя библиотека имеет дело с несколькими bean-компонентами (перехватчиками), указанными в произвольном порядке (поскольку они распределены по нескольким файлам конфигурации). Прежде чем я смогу применить их, я должен отсортировать их по приоритету. Я использую AnnotationAwareOrderComparator.sort(beans) для этого. Это хорошо работает, пока аннотация @Order добавляется на уровне класса этого перехватчика. Но это не работает, когда я пытаюсь использовать его в классах @Configuration в методах @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) всегда возвращает null (не указано) для порядка этих бобов. Вероятно, потому что экземпляры bean-компонентов не проксируются и, следовательно, не реализуют порядок и не имеют аннотации порядка на уровне своего класса. Есть ли BeanPostProcessor или параметр конфигурации, который я должен включить?

Сортировка spring @Beans по уровню метода аннотации @Order

Как мне указать Spring либо сохранить аннотированный порядок, либо использовать определения bean-компонентов контекста приложения для правильной сортировки bean-компонентов?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
5
0
796
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Чтобы ваш тестовый пример работал, вам нужно использовать интерфейс Ordered вместо аннотации. Давайте рассмотрим исходный код AnnotationAwareOrderComparator. Обратите внимание, что вы передаете объекты непосредственно методу сортировки. Компаратор AnnotationAwareOrderComparator использует findOrder для промежуточных объектов, чтобы найти один из трех артефактов @Priority аннотацию @Order аннотацию или @Ordered интерфейс. В вашем случае вы передаете экземпляры перехватчика, поэтому проверка if для Methidf и для класса вернет false. Вы нажмете последний метод if: if (obj != null)

в этом случае он просто проверит ваш объект clas для аннотации @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;
    }

Тогда почему я могу поместить аннотацию заказа в этот метод? Однако в javadoc нет ничего, что говорило бы о том, что вы не можете использовать его для объявлений @Bean. Spring использует прокси и подобные конструкции во многих местах, почему бы и нет в этом случае? Подкласс класса bean-компонента только для того, чтобы установить порядок, кажется неправильным.

ST-DDT 04.06.2019 10:21

@ST-DDT можно использовать, и при запуске это учитывается. Но это до того, как у вас будет настоящий экземпляр. В вашем тестовом случае это не тот порядок, который вы используете неправильно, это AnnotationAwareOrderComparator. Вы ожидаете, что он будет работать с инициализированным экземпляром, а это не так. Согласно документации при запуске Приказ должен быть применен корректно. Поэтому, если вы поместите Autowire в список перехватчиков в своем тесте, они должны быть правильно упорядочены.

Alexander Petrov 04.06.2019 10:52

Другие вопросы по теме