Camel JMS路由连接IBM MQ成功后立即自动关闭问题咨询
看起来你遇到的问题是:Spring Boot集成Camel连接IBM MQ时,应用明明启动成功(路由正常启动、MQ连接测试通过),但立刻就开始关闭上下文,而连接ActiveMQ时却能正常运行。从你提供的日志片段能看到关键节点:
2018-01-23 12:13:05:563 se.tradechannel.IbmMqApplication INFO - Started IbmMqApplication in 37.347 seconds [...]
2018-01-23 12:13:05:766 o.a.camel.spring.SpringCamelContext DEBUG - onApplicationEvent: org.springframework.context.event.ContextClosedEvent[...]
结合场景来看,最可能的原因是Spring Boot没有非守护线程保持应用活跃,下面是具体的分析和解决办法:
1. 非Web类型Spring Boot应用的默认行为
如果你的应用没有引入Web相关依赖(比如spring-boot-starter-web),Spring Boot在启动完成后,会因为没有需要持续运行的非守护线程,自动关闭ApplicationContext。而ActiveMQ的消费者线程默认是非守护线程,所以能让应用保持运行;IBM MQ的消费者线程可能被默认设置为守护线程,导致应用启动后立刻退出。
解决办法
方法一:添加Web依赖并设置为非Web应用
在你的pom.xml中添加Web依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
然后在application.properties里配置:
spring.main.web-application-type=none
这样既不会启动Web容器,又能让Spring Boot保持应用运行状态。
方法二:手动添加阻塞主线程的Bean
如果不想引入Web依赖,可以在启动类里添加一个ApplicationRunner Bean,用来阻塞主线程:
@SpringBootApplication public class IbmMqApplication { public static void main(String[] args) { SpringApplication.run(IbmMqApplication.class, args); } @Bean public ApplicationRunner keepAppAlive() { return args -> { // 阻塞主线程,防止应用关闭 Thread.currentThread().join(); }; } }
2. 强制设置IBM MQ连接的线程为非守护线程
IBM MQ的MQConnectionFactory默认可能创建守护线程,你可以显式修改这个配置:
在你的websphereConnectionFactory()方法中添加一行:
import com.ibm.mq.jms.WMQConstants; // ... 其他配置代码 ... connectionFactory.setBooleanProperty(WMQConstants.WMQ_CLIENT_NON_DAEMON_THREADS, true);
这个配置会让IBM MQ客户端创建的线程变为非守护线程,从而让Spring Boot感知到活跃线程,避免自动关闭。
3. 调整Camel JMS组件的线程配置
你也可以直接修改Camel JMS组件使用的消息监听器容器,强制设置线程为非守护线程:
// 在配置JmsComponent的代码中添加: final DefaultJmsListenerContainerFactory containerFactory = new DefaultJmsListenerContainerFactory(); containerFactory.setConnectionFactory(connectionFactory); // 自定义线程池,设置非守护线程 containerFactory.setTaskExecutor(new SimpleAsyncTaskExecutor() { @Override protected Thread createThread(Runnable runnable) { Thread thread = super.createThread(runnable); thread.setDaemon(false); // 关键:设置为非守护线程 return thread; } }); jmsComponent.setListenerContainerFactory(containerFactory);
验证线程状态
如果还不确定问题所在,可以添加一个监听器,在应用启动后打印所有线程的状态,看看是否有非守护线程在运行:
@EventListener(ApplicationReadyEvent.class) public void logThreadStatus() { ThreadGroup rootGroup = Thread.currentThread().getThreadGroup(); while (rootGroup.getParent() != null) { rootGroup = rootGroup.getParent(); } Thread[] threads = new Thread[rootGroup.activeCount()]; rootGroup.enumerate(threads); for (Thread thread : threads) { if (thread != null) { System.out.printf("线程名称:%s,是否守护线程:%b%n", thread.getName(), thread.isDaemon()); } } }
如果所有和IBM MQ、Camel相关的线程都是true(守护线程),那就是导致应用关闭的直接原因。
内容的提问来源于stack exchange,提问作者Katarina Stubberud

