2017-07-06 57 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 
    } 
}