Tomcat通过Spring Integration Java DSL暂停关机

时间:2017-04-03 20:40:47

标签: java spring spring-integration

我有一个问题,试图优雅地关闭Tomcat(8)永远不会完成,因为看起来DefaultMessageListenerContainer被无限期地阻塞(或循环)。

我一直在谷歌搜索解决方案,但我发现的任何类似的东西都没有用。这包括(但不限于):

  • 使用configureListenerContainer()设置容器的taskExecutor
  • 使用Messages.queue()代替Messages.direct()
  • ActiveMQConnectionFactory包裹在CachingConnectionFactory

一个简单的Servlet 3.0示例:

compile 'org.springframework.integration:spring-integration-core:4.3.6.RELEASE'
compile 'org.springframework.integration:spring-integration-jms:4.3.6.RELEASE'
compile 'org.springframework.integration:spring-integration-java-dsl:1.2.1.RELEASE'

初​​始化器:

public class ExampleWebApp implements WebApplicationInitializer {
    @Override
    public void onStartup(final ServletContext servletContext) throws ServletException {
        final AnnotationConfigWebApplicationContext springContext = new AnnotationConfigWebApplicationContext();
        springContext.register(ExampleConfig.class);

        servletContext.addListener(new ContextLoaderListener(springContext));

        final ServletRegistration.Dynamic registration = servletContext.addServlet("example", new HttpRequestHandlerServlet());
        registration.setLoadOnStartup(1);
        registration.addMapping("/status");
    }
}

配置:

@Configuration
@EnableIntegration
public class ExampleConfig {
    @Bean
    public ConnectionFactory connectionFactory() {
        final ActiveMQConnectionFactory mqConnectionFactory = new ActiveMQConnectionFactory();
        mqConnectionFactory.setBrokerURL("tcp://host:port");
        mqConnectionFactory.setUserName("----");
        mqConnectionFactory.setPassword("----");

        return mqConnectionFactory;
    }

    @Bean
    public Queue testQueue() {
        return new ActiveMQQueue("test.queue");
    }

    @Bean
    public MessageChannel testReceiveChannel() {
        return MessageChannels.direct().get();
    }

    @Bean
    public IntegrationFlow pushMessageInboundFlow() {
        return IntegrationFlows
                .from(Jms.messageDrivenChannelAdapter(connectionFactory())
                         .destination(testQueue()))
                .log()
                .transform(new JsonToObjectTransformer(TestMessageObject.class))
                .channel(testReceiveChannel())
                .get();
    }

    /** Example message object */
    public static class TestMessageObject {
        private String text;

        public String getText() {
            return text;
        }

        public void setText(final String text) {
            this.text = text;
        }
    }
}

如果我尝试通过catalina.sh脚本停止此操作(例如,按下"停止"在Intellij",它永远不会完成现有。到目前为止,我唯一的方法是能够关闭完成是通过一个小帮助类手动"在关机时销毁JmsMessageAdapters:

public class JmsMessageListenerContainerLifecycleManager {
    private static final Logger LOG = LoggerFactory.getLogger(JmsMessageListenerContainerLifecycleManager.class);

    @Autowired
    private List<IntegrationFlow> mIntegrationFlows;

    @PreDestroy
    public void shutdownJmsAdapters() throws Exception {
        LOG.info("Checking {} integration flows for JMS message adapters", mIntegrationFlows.size());

        for (IntegrationFlow flow : mIntegrationFlows) {
            if (flow instanceof StandardIntegrationFlow) {
                final StandardIntegrationFlow standardFlow = (StandardIntegrationFlow) flow;

                for (Object component : standardFlow.getIntegrationComponents()) {
                    if (component instanceof JmsMessageDrivenChannelAdapter) {
                        final JmsMessageDrivenChannelAdapter adapter = (JmsMessageDrivenChannelAdapter) component;

                        LOG.info("Destroying JMS adapter {}", adapter.getComponentName());
                        adapter.destroy();
                    }
                }
            }
        }
    }
}

虽然这有效,但它肯定是错误的解决方案。

以前我使用的是spring-integration的XML配置,我没有遇到这个问题。我错过了什么?

1 个答案:

答案 0 :(得分:1)

唉!这绝对是个错误。看起来你正确地解决了它。

虽然考虑在那里销毁任何DisposableBean

我将修复程序添加到Spring Integration Java DSL。我们将在Spring Integration 1.2.2之后发布下一个4.3.9

Spring Integration 5.0将在明天的M3版本中修复。