MDP JMS事务回滚然后在无限循环中重新处理消息

时间:2011-06-30 17:26:04

标签: java spring jms

如果我通过指定sessionTransacted=truetransactionManager=jmsTransactionManager在我的DefaultMessageListenerContainer上启用事务管理,则只要MDP中发生异常,就会回滚事务并将消息放回队列中。然后导致消息再次被处理,事务再次反复回滚,以便创建无限循环。

我想我的问题是......我在这里错过了什么?如果只是意味着它将被反复处理,为什么你希望消息返回队列?

<!-- jms connection factory -->
<bean name="jmsConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="java:ConnectionFactory" />
</bean>

<!-- jms transaction manager -->
<bean id="jmsTransactionManager" class="org.springframework.jms.connection.JmsTransactionManager">
    <property name="connectionFactory" ref="jmsConnectionFactory" />
</bean>

<!-- Destination for Inbound_Email_Q -->
<bean name="inboundEmailDestination" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="queue/inbound_Email_Queue" />
</bean>

<!-- JmsTemplate for Inbound_Email_Q -->
<bean name="jmsInboundEmailTemplate" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="jmsConnectionFactory" />
    <property name="defaultDestination" ref="inboundEmailDestination" />
    <property name="messageConverter" ref="xmlMessageConverter" />
</bean>

<!-- jms asynchronous listener -->
<bean id="emailMessageServiceMdp" class="org.site.wso.core.jms.EmailMessageServiceMdp" />
<bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="connectionFactory" ref="jmsConnectionFactory"/>
    <!-- <property name="transactionManager" ref="jmsTransactionManager" />  -->
    <!-- <property name="sessionTransacted" value="true"/>  -->
    <property name="destination" ref="inboundEmailDestination"/>
    <property name="messageListener" ref="messageListener"/>
</bean>

<!-- jms message listener adapter -->
<bean id="messageListener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
    <constructor-arg>
        <bean class="org.site.wso.core.jms.EmailMessageServiceMdp"/>
    </constructor-arg>
    <property name="messageConverter" ref="xmlMessageConverter"/>
</bean>

这是我的MDP:

public class EmailMessageServiceMdp implements MessageDelegate {

    public void handleMessage(Object object) {

        EmailMessageRequestVO requestVO = (EmailMessageRequestVO) object;   

        try {
            //Service call that throw exception
        } catch (Exception e) {
            throw new ApplicationException(e);
        }

    }
}

1 个答案:

答案 0 :(得分:3)

消息重新传递只是[配置] JMS实现的默认行为。关于这个问题的相对有用性是多么无休止的争论,但似乎不是丢弃带有一些潜在的不可恢复数据的信息,而是某种重试是一种明智和保守的方法。例如,在您的情况下,您似乎正在将JMS邮件转换为电子邮件并分派到SMTP服务器。如果SMTP网关关闭,您可能希望保留JMS消息并在网关重新启动时重新处理它们。

一般来说,我会说您处理处理失败的消息的选项是(取决于JMS实现):

  1. 抛弃信息。
  2. 将邮件写入错误队列。
  3. 延迟 n 秒后重新发送消息。
  4. 重新发送消息 n 次,然后将消息写入错误队列。
  5. n x 次延迟后重新传递消息,然后将消息写入错误队列。
  6. 如果您更喜欢#1,那么只需抑制异常,提交事务并向消息挥手告别。对于其余部分,JMS配置(或目标特定配置)应该处理这些。

    此外,如果您想要更具体的内容,可以查询消息的getJMSRedelivered()和/或特定于实现的消息头属性,该属性指示消息被重新传递的次数(大多数JMS实现支持,但不是标准)并相应处理消息。