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