2017-07-06 139 views
0

我有一些我需要重构的旧代码,它具有JMS的编程事务管理。Spring JMS - 声明式事务管理使用注释

有一个计划的服务,它可以同步读取所有消息(使用JMS)并逐个处理它们。我正在使用JmsTransactionManager进行交易。我可以用声明式事务管理使用注释来管理每封邮件我的交易,而不是他们的管理程序,像这样:

//code from scheduled service's run method 
private void run() 
{ 
    javax.jms.Message jmsMessage = null; 
    do 
    { 
     TransactionStatus status = null; 
     try 
     { 
      status = jmsTransactionManager.getTransaction(new DefaultTransactionDefinition()); 
      jmsMessage = jmsTemplate.receive(heldTransmissionDestination); 
      if(jmsMessage != null) 
      { 

       process(jmsMessage); 
       jmsMessage.acknowledge(); //session is still open within the transaction 
      } 
      jmsTransactionManager.commit(status); 
     } 
     catch(Exception e) 
     { 
      logger.error("Exception: ", e); 
      if(status != null) 
      { 
       jmsTransactionManager.rollback(status); 
       logger.info("JMSTransaction rollback successful"); 
      } 
      //since an exception occured, break out of the do-while 
      break; 
     } 
    } 
    while(jmsMessage != null); 
} 

请注意,此代码的工作。为JmsTemplate的配置已sessionTrasacted设置为true,如下图所示:

// from config 
@Bean 
public JmsTemplate jmsTemplate() { 
    JmsTemplate jmsTemplate = new JmsTemplate(); 
    jmsTemplate.setSessionTransacted(true); 
    // ... other stuff ommited for brevity 
    return jmsTemplate; 
} 

回答

1

我尝试过了,它不带有注释的工作。然而,有几个注意事项:

首先,是利用在配置中@EnableTransactionManagement的(如果你使用纯Java DSL),像这样:

@Configuration 
@EnableTransactionManagement 
public class JmsConfig { 

    @Bean 
    public JmsTemplate jmsTemplate() { 
     JmsTemplate jmsTemplate = new JmsTemplate(); 
     jmsTemplate.setSessionTransacted(true); 
     // ... other stuff ommited for brevity 
     return jmsTemplate; 
    } 

    @Bean 
    public JmsTransactionManager jmsTransactionManager() { 
     JmsTransactionManager jmsTransactionManager = new JmsTransactionManager(); 
     jmsTransactionManager.setConnectionFactory(jmsConnectionFactory()); 
     return jmsTransactionManager; 
    } 

    //other bean definitions omitted for brevity 
} 

或者你可以做这样的事情在你的XML配置而不是上述:

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

其次,是这样的交易是proxied(AOP)。正因为如此,需要在事务中的逻辑需要移动到另一个类中,以便它可以被代理。请注意,如果您只是将其命名为transactionManager,Spring会自动检测您的事务管理器。但就我而言,我有多个这样的bean,所以我必须明确地使用这个bean;并在我的注释的值属性中引用它,如下所示:

public class ServiceToSchedule 
{ 

    @Autowired 
    private JmsMessageProcessor jmsMessageProcessor; 

    public void run() 
    { 
     Message jmsMessage = null; 

     do 
     { 
      try { 
       jmsMessage = jmsMessageProcessor.readAndProcessMessage(); 
      } catch (JMSException e) { 
       logger.debug("JMSException processing heldTransmission: ", e); 
       break; 
      } catch (Exception e) { 
       logger.debug("Exception processing heldTransmission: ", e); 
       break; 
      } 

     } 
     while(jmsMessage != null); 
    } 
} 

public class JmsMessageProcessor 
{ 

    @Transactional(value="jmsTransactionManager", propagation = Propagation.REQUIRES_NEW) 
    public Message readAndProcessMessage() throws JMSException 
    { 
     Message jmsMessage = jmsTemplate.receive(heldTransmissionDestination); 
     if(jmsMessage != null) 
     { 
      process(jmsMessage); 
     } 
     //have to return to break out of the while in the caller 
     return jmsMessage; 
    } 

    @Transactional(value="jmsTransactionManager", propagation = Propagation.NESTED) 
    protected void process(Message jmsMessage) 
    { 
     //code to process the jmsMessage, can potentially throw 
     //an exception that requires rolling back the jms transaction 
    } 
}