Spring-Integration:确保 IntegrationRequestMappingHandlerMapping 已初始化

Spring-Integration: Ensure that IntegrationRequestMappingHandlerMapping is initialized

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();
    }
}

效果是,当其他 bean 在应用程序启动期间尝试对其求值时,其 mappingRegistry 为空,即使它们以 MAX_VALUE.[=23 阶段实现 SmartLifeCycle 也是如此=]

在我的例子中,我正在尝试为 Springfox 实现一个 spring 集成插件。它 DocumentationPluginsBootstrapper 需要访问请求映射以记录它们。

在我开始请求其映射之前,如何确定 IntegrationRequestMappingHandlerMapping 已经初始化?监听 ContextRefreshedEvent 是否也是正确的方法,但是 @Order 的值很高?或者您会建议使用不同的事件吗?

更新:AbstractHandlerMapping 已经使用 Order.LOWEST_PRECEDENCE。我想我不能使用上下文刷新事件来保证安全。

另见 related springfox issue

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()被解雇了。

您确实应该考虑 OrderedOrder.LOWEST_PRECEDENCEApplicationListener<ContextRefreshedEvent>。同时框架注册 IntegrationRequestMappingHandlerMappingorder == 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);
    }
}