Spring-Integration: убедитесь, что IntegrationRequestMappingHandlerMapping инициализирован - PullRequest
0 голосов
/ 28 октября 2018

IntegrationRequestMappingHandlerMapping имеет специальное требование для инициализации на ContextRefreshedEvent.Чтобы процитировать код:

@Override
public void afterPropertiesSet() {
    // No-op in favor of onApplicationEvent
}

/**
 * {@link HttpRequestHandlingEndpointSupport}s may depend on auto-created
 * {@code requestChannel}s, so MVC Handlers detection should be postponed
 * as late as possible.
 * @see RequestMappingHandlerMapping#afterPropertiesSet()
 */
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
    if (!this.initialized.getAndSet(true)) {
        super.afterPropertiesSet();
    }
}

В результате его mappingRegistry становится пустым, когда другие компоненты пытаются оценить его во время запуска приложения, даже если они реализуют SmartLifeCycle с фазой MAX_VALUE.

В моем случае я пытаюсь реализовать плагин интеграции с пружиной для Springfox .Для DocumentationPluginsBootstrapper необходим доступ к сопоставлениям запросов для их документирования.

Как я могу быть уверен, что IntegrationRequestMappingHandlerMapping был инициализирован до того, как я начну запрашивать его сопоставления?Будет ли правильным тоже слушать ContextRefreshedEvent, но с высоким значением @Order?Или вы бы посоветовали использовать другое событие?

Обновление: AbstractHandlerMapping уже использует Order.LOWEST_PRECEDENCE.Наверное, я не могу использовать событие обновления контекста, чтобы быть безопасным.

Также см. связанную проблему springfox .

1 Ответ

0 голосов
/ 29 октября 2018

ContextRefreshedEvent на самом деле является последним шагом в инициализации контекста приложения:

            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);

            // Invoke factory processors registered as beans in the context.
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            initMessageSource();

            // Initialize event multicaster for this context.
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            onRefresh();

            // Check for listener beans and register them.
            registerListeners();

            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            finishRefresh();

Он запускается в этом finishRefresh().

Вы действительно должны рассмотреть Ordered для своего ApplicationListener<ContextRefreshedEvent> с Order.LOWEST_PRECEDENCE.В то же время Framework регистрирует это IntegrationRequestMappingHandlerMapping с помощью order == 0:

private void registerRequestMappingHandlerMappingIfNecessary(BeanDefinitionRegistry registry) {
    if (HttpContextUtils.WEB_MVC_PRESENT &&
            !registry.containsBeanDefinition(HttpContextUtils.HANDLER_MAPPING_BEAN_NAME)) {
        BeanDefinitionBuilder requestMappingBuilder =
                BeanDefinitionBuilder.genericBeanDefinition(IntegrationRequestMappingHandlerMapping.class);
        requestMappingBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        requestMappingBuilder.addPropertyValue(IntegrationNamespaceUtils.ORDER, 0);
        registry.registerBeanDefinition(HttpContextUtils.HANDLER_MAPPING_BEAN_NAME,
                requestMappingBuilder.getBeanDefinition());
    }
}

Таким образом, вы действительно можете сохранить отображение в своем собственном слушателе.Просто потому, что благодаря order = 0 IntegrationRequestMappingHandlerMapping будет уже инициализирован.

То же самое относится к WebFluxIntegrationRequestMappingHandlerMapping:

private void registerReactiveRequestMappingHandlerMappingIfNecessary(BeanDefinitionRegistry registry) {
    if (HttpContextUtils.WEB_FLUX_PRESENT &&
            !registry.containsBeanDefinition(WebFluxContextUtils.HANDLER_MAPPING_BEAN_NAME)) {
        BeanDefinitionBuilder requestMappingBuilder =
                BeanDefinitionBuilder.genericBeanDefinition(WebFluxIntegrationRequestMappingHandlerMapping.class);
        requestMappingBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        requestMappingBuilder.addPropertyValue(IntegrationNamespaceUtils.ORDER, 0);
        registry.registerBeanDefinition(WebFluxContextUtils.HANDLER_MAPPING_BEAN_NAME,
                requestMappingBuilder.getBeanDefinition());

        BeanDefinitionReaderUtils.registerWithGeneratedName(
                new RootBeanDefinition(IntegrationHandlerResultHandler.class), registry);
    }
}
...