Spring integration 干净地关闭Spring集成(使用RabbitMQ)

Spring integration 干净地关闭Spring集成(使用RabbitMQ),spring-integration,spring-rabbit,Spring Integration,Spring Rabbit,我使用的是:Spring Boot 1.4.7、Spring Integration 4.3.10、RabbitMQ 3.6.5 我有一个Spring引导应用程序,它有几个Spring集成流,可以向rabbitMQ代理发送和接收消息 我遇到一个问题,当调用“关机”执行器时,应用程序并不总是干净地关机 在执行线程转储后,我可以看到单个“SimpleMessageListenerContainer”线程在对代理执行“发送”操作时被阻塞: "org.springframework.amqp.rabbi

我使用的是:Spring Boot 1.4.7、Spring Integration 4.3.10、RabbitMQ 3.6.5

我有一个Spring引导应用程序,它有几个Spring集成流,可以向rabbitMQ代理发送和接收消息

我遇到一个问题,当调用“关机”执行器时,应用程序并不总是干净地关机

在执行线程转储后,我可以看到单个“SimpleMessageListenerContainer”线程在对代理执行“发送”操作时被阻塞:

"org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer#0-1" #81 prio=5 os_prio=0 tid=0x00007fe49bcac800 nid=0x4fc5 waiting on condition [0x00007fe489efe000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000006c259a6f8> (a java.util.concurrent.SynchronousQueue$TransferStack)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:458)
    at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
    at java.util.concurrent.SynchronousQueue.put(SynchronousQueue.java:877)
    at org.springframework.integration.channel.QueueChannel.doSend(QueueChannel.java:93)
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:423)
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:373)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45)
    at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:105)
    at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutput(AbstractMessageProducingHandler.java:358)
    at org.springframework.integration.handler.AbstractMessageProducingHandler.produceOutput(AbstractMessageProducingHandler.java:269)
    at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutputs(AbstractMessageProducingHandler.java:186)
    at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:115)
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127)
    at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116)
    at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:148)
    at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:121)
    at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:89)
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:423)
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:373)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45)
    at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:105)
    at org.springframework.integration.endpoint.MessageProducerSupport.sendMessage(MessageProducerSupport.java:188)
    at org.springframework.integration.amqp.inbound.AmqpInboundChannelAdapter.access$1100(AmqpInboundChannelAdapter.java:56)
    at org.springframework.integration.amqp.inbound.AmqpInboundChannelAdapter$Listener.processMessage(AmqpInboundChannelAdapter.java:246)
    at org.springframework.integration.amqp.inbound.AmqpInboundChannelAdapter$Listener.onMessage(AmqpInboundChannelAdapter.java:203)
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:823)
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:746)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$001(SimpleMessageListenerContainer.java:99)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$1.invokeListener(SimpleMessageListenerContainer.java:191)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.invokeListener(SimpleMessageListenerContainer.java:1238)
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:727)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:1192)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:1176)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1100(SimpleMessageListenerContainer.java:99)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1370)
    at java.lang.Thread.run(Thread.java:745)
然而,我确实发现了几个异常值:

@Bean(name=CHANNEL_NAME_ID_MAIL_IN)
public MessageChannel channelIdMailIn() {
    //Using a rendezvous channel on inbound because we use a rest endpoint to pull messages rather than using a push model
    return MessageChannels.rendezvous().get();
}
@Bean(name=CHANNEL_NAME_CATEGORY_REFRESH_PRODUCTION_OUT)
public MessageChannel channelCategoryRefreshProductionOut() {
    return MessageChannels.publishSubscribe().get();
}
感谢您的快速反馈,我将进一步探索这一途径

位于org.springframework.integration.channel.QueueChannel.doSend(QueueChannel.java:93)

看起来您正在使用入站通道适配器的有界
QueueChannel
下游

adapter->DirectChannel->someEndpoint->QueueChannel<-somePoller

adapter->DirectChannel->someEndpoint->QueueChannel只是为了跟进对我有效的解决方案。选项2起了很大的作用。我创建了一个新的任务执行器,并将waitForTasksToCompleteOnShutdown设置为“false”。加里,非常感谢你的帮助

@Bean
public TaskExecutor taskExecutorIdMailIn(
        @Value("${taskExecutor.idMailIn.corePoolSize:4}") int corePoolSize,
        @Value("${taskExecutor.idMailIn.maxPoolSize:4}") int maxPoolSize, 
        @Value("${taskExecutor.idMailIn.queueCapacity:0}") int queueCapacity) {

    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    taskExecutor.setThreadNamePrefix("taskExecutorIdMailIn-");
    taskExecutor.setCorePoolSize(corePoolSize);
    taskExecutor.setMaxPoolSize(maxPoolSize);
    if (queueCapacity > 0) {
        taskExecutor.setQueueCapacity(queueCapacity);
    }
    taskExecutor.setRejectedExecutionHandler(new CallerRunsPolicy());
    taskExecutor.setWaitForTasksToCompleteOnShutdown(false);
    return taskExecutor;
}   

@Bean
public IntegrationFlow flowRabbitToIdMailIn(ConnectionFactory factory, @Qualifier("taskExecutorIdMailIn") TaskExecutor taskExecutor) {
    return IntegrationFlows
            .from(Amqp.inboundAdapter(factory, queueNameIdMail)
                    .taskExecutor(taskExecutor)
                    .errorHandler(errorHandler)
            )
            .transform(Transformers.fromJson())
            .channel(CHANNEL_NAME_ID_MAIL_IN)
            .get();
}

它与RabbitMQ无关-线程卡在内存队列中;看到我的答案了。Gary,在做了一些挖掘之后,我的问题是会合频道,因为它扩展了队列频道。在我对上下文发出关闭之前/之后,是否有方法正确关闭此通道?我们需要支持这个愚蠢的东西,因为我们有一个遗留的ColdFusion(yes CF),它轮询一个端点以检查队列中的消息。
@Bean
public TaskExecutor taskExecutorIdMailIn(
        @Value("${taskExecutor.idMailIn.corePoolSize:4}") int corePoolSize,
        @Value("${taskExecutor.idMailIn.maxPoolSize:4}") int maxPoolSize, 
        @Value("${taskExecutor.idMailIn.queueCapacity:0}") int queueCapacity) {

    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    taskExecutor.setThreadNamePrefix("taskExecutorIdMailIn-");
    taskExecutor.setCorePoolSize(corePoolSize);
    taskExecutor.setMaxPoolSize(maxPoolSize);
    if (queueCapacity > 0) {
        taskExecutor.setQueueCapacity(queueCapacity);
    }
    taskExecutor.setRejectedExecutionHandler(new CallerRunsPolicy());
    taskExecutor.setWaitForTasksToCompleteOnShutdown(false);
    return taskExecutor;
}   

@Bean
public IntegrationFlow flowRabbitToIdMailIn(ConnectionFactory factory, @Qualifier("taskExecutorIdMailIn") TaskExecutor taskExecutor) {
    return IntegrationFlows
            .from(Amqp.inboundAdapter(factory, queueNameIdMail)
                    .taskExecutor(taskExecutor)
                    .errorHandler(errorHandler)
            )
            .transform(Transformers.fromJson())
            .channel(CHANNEL_NAME_ID_MAIL_IN)
            .get();
}