Spring Boot集成Atomikos调用JMS时出现JTA异常如何解决?
问题解决方案
1. setDeliveryDelay的AbstractMethodError报错
报错原因
你使用的Atomikos 4.x版本不支持JMS 2.0新增的setDeliveryDelay方法,导致方法调用时出现抽象方法错误。
修复方案
- 不需要延迟发送的话,保留你当前注释
jmsTemplate.setDeliveryDelay(5000L);的处理即可 - 需要使用延迟发送特性,将所有Atomikos相关依赖版本统一升级到5.x及以上,即可支持JMS 2.0特性
2. JTA事务上下文缺失报错
报错原因
你添加的@Transactional注解不生效,核心原因是:Spring事务注解仅对Spring容器管理的Bean的非静态方法生效,你直接在静态的main方法中调用JmsTemplate,事务切面无法拦截到该调用,也就不会自动开启JTA事务。
修复方案
按优先级推荐以下两种处理方式:
方案一:抽离发送逻辑,正确使用事务注解
- 首先在启动类上添加
@EnableTransactionManagement注解开启事务自动管理 - 将消息发送逻辑抽离为Spring Bean的非静态方法,添加
@Transactional注解 - 监听端的容器工厂添加事务管理器配置,保证消费端事务生效
修改后的完整代码示例:
@SpringBootApplication @EnableTransactionManagement // 新增:开启事务管理 public class Application { private static Logger logger = LoggerFactory.getLogger(Application.class); @Autowired private JmsTemplate jmsTemplate; @Bean public JmsListenerContainerFactory<DefaultMessageListenerContainer> connectionFactory(ConnectionFactory connectionFactory, DefaultJmsListenerContainerFactoryConfigurer configurer, PlatformTransactionManager transactionManager) { DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); configurer.configure(factory, connectionFactory); // 新增:配置事务管理器,开启会话事务 factory.setTransactionManager(transactionManager); factory.setSessionTransacted(true); return factory; } // 新增:抽离发送逻辑,添加事务注解 @Transactional public void sendMessages() { for (int i = 0; i < 10; ++i) { logger.info(">>> Sending: Test message: " + i); jmsTemplate.convertAndSend("prospring5", "Test message: " + i); } } public static void main(String... args) throws Exception { ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args); // 从容器中获取Bean实例,调用带事务注解的方法 Application app = ctx.getBean(Application.class); app.sendMessages(); System.in.read(); ctx.close(); } @JmsListener(destination = "prospring5", containerFactory = "connectionFactory") public void onMessage(Message message) { TextMessage textMessage = (TextMessage) message; try { logger.info(">>> Received: " + textMessage.getText()); } catch (JMSException ex) { logger.error("JMS error", ex); } } }
方案二:无需分布式事务的简化配置
如果你的场景不需要跨资源的分布式JTA事务,可以直接在application.properties中添加以下配置,使用本地事务即可:
# 开启Atomikos本地事务模式,不需要开启JTA全局事务 spring.jta.atomikos.connectionfactory.local-transaction-mode=true # 调整连接池大小,避免连接不足报错 spring.jta.atomikos.connectionfactory.max-pool-size=20
额外优化建议
你依赖中引入的com.atomikos:transactions-hibernate4属于多余依赖,如果项目没有用到Hibernate可以直接删除,避免版本冲突:Spring Boot 2.0.6默认自带的Atomikos版本为4.0.6,你单独引入的4.0.4版本会导致依赖版本不一致,是第一个方法缺失报错的核心诱因之一。
内容的提问来源于stack exchange,提问作者fangtasticmr Z
相关产品推荐
相关产品推荐

