首页 文章

虽然异常在ErrorHandler中处理,但Spring JMS与JTA回滚

提问于
浏览
1

我通过Atomikos和JMS使用Spring Integration和JTA支持绑定到不同的Webshpere MQ和Oracle数据库 .
对于其他人而言,它似乎与_2732233中的线程相同,但它根本不是 .
流程如下:

  • message-driven-channel-adapter接收事务内的消息

  • 一些转变

  • ServiceActivator具有更深层次的业务逻辑

  • 数据库更新

对于一个szenario来说,一切都很顺利:
如果在ServiceActivator中发生未经检查的异常(可能是由于不应该存在的不一致数据),则会在ErrorHandler(通过ErrorChannel)中重新抛出并处理该消息 . 在某些情况下,应该将orgininal传入消息发送到DeadLetter队列(Webshere MQ) . 这是通过出站通道适配器完成的 .

见封闭配置:

<jms:message-driven-channel-adapter id="midxMessageDrivenAdapter"
                                            channel="midxReplyChannel"
                                            acknowledge="auto"
                                            transaction-manager="transactionManager"
                                            connection-factory="connectionFactory"
                                            concurrent-consumers="1"
                                            error-channel="errorChannel"
                                            max-concurrent-consumers="${cmab.integration.midx.max.consumer}"
                                            idle-task-execution-limit="${cmab.integration.midx.idleTaskExecutionLimit}"
                                            receive-timeout="${cmab.integration.midx.receiveTimeout}"
                                            destination="midxReplyQueue"/>
................
<int:service-activator input-channel="midxReplyProcessChannel" ref="processMidxReplyDbWriter" />

        <int:service-activator input-channel="errorChannel" ref="inputErrorHandler" />

        <jms:outbound-channel-adapter id="deadLetterOutboundChannelAdapter"
                                      channel="errorDlChannel" destination="deadLetterQueue"
                                      delivery-persistent="true" connection-factory="nonXAConnectionFactory"/>

Some important hints: 消息驱动通道适配器:

  • connectionFactory是一个MQXAQueueConnectionFactory,它与AtomikosConnectionFactoryBean相连

  • transaction-manager是Spring JtaTransactionManager

出站通道适配器:
connection-factory是一个非XAConnectionFactory .

CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
.....
cachingConnectionFactory.setTargetConnectionFactory(mqQueueConnectionFactory);
return cachingConnectionFactory;

And now the error which I observed:
虽然我在ErrorHandler中处理了未经检查的异常(ref = "inputErrorHandler";将消息发送到DeadLetter-Queue),但是启动了回滚,并且消息驱动通道适配器一次又一次地接收消息 .
实际上,消息是通过出站通道适配器传递给DeadLetterQueue的事实 . 目标(deadLetterQueue)包含失败的消息 .

问题:我做错了什么?虽然我在ErrorHandler中处理了异常,但回滚失败的原始传入消息 .

任何帮助真的很感激 . 提前谢谢了 .

1 回答

  • 0

    关于我的评论,请参阅我的InputErrorHandler的代码:

    if (throwable instanceof MessageHandlingException) {
    
                MessageHandlingException messageHandlingException = (MessageHandlingException) throwable;
    
                if (messageHandlingException.getCause() != null
                        && (messageHandlingException.getCause() instanceof CmabProcessDbException
                        || messageHandlingException.getCause() instanceof CmabReplyFormatException)) {
    
                    String appMessage = ((CmabException) messageHandlingException.getCause()).getAppMessagesAsString();
    
                    LOGGER.error(String.format("cmab rollback exception occured: %s", appMessage));
                    LOGGER.error("******** initiate rollback *********");
    
                    throw throwable.getCause();
    
                } else {
    
                    ErrorDto payload = fillMessagePayload(messageHandlingException, throwableClassName);
                    sendMessageToTargetQueue(payload);
                }
    

    正如我所提到的,“business”ServiceActivator会抛出一个未经检查的异常,因此在这种情况下,ELSE-Statements正在调用 . 在其中,我使用MessagBuilder构建一个Message并将其发送到errorDlChannel(s . 在出站通道适配器上方!) .

    private void sendMessageToDeadLetterQueue(Message<?> message, String description, String cause) {
    
    .......
    
            Message<?> mb =
                    MessageBuilder.withPayload(message.getPayload())
                            .copyHeaders(message.getHeaders())
                            .setHeaderIfAbsent("senderObject", this.getClass().getName())
                            .setHeaderIfAbsent("errorText", description)
                            .setHeaderIfAbsent("errorCause", errorCause).build();
    
            errorDlChannel.send(mb);
    
        }
    

    就这样 . 对于这种情况,这是最后一个陈述 . 我的ErrorHandler的main方法中没有任何其他内容 . 没有重新抛出或其他东西 .
    所以这就是我困惑的原因 . 对我来说,异常是通过将它发送到errorDlChannel(outbound-channel-adapter - > DeadLetterQueue)来处理的 .
    我在DeadLetter Queue上看到了这条消息,但仍然发生了jta回滚......而IMO这不应该是蜜蜂 .

相关问题