Spring JMS - 使用注解的声明式事务管理
Spring JMS - Declarative Transaction Management Using Annotations
我有一些旧代码需要重构,其中包含 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;
}
我试过了,它确实适用于注释。但是,有几点需要注意:
首先,是在您的配置中使用 @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)。因此,需要在一个事务中的逻辑需要移动到另一个 class 以便它可以被代理。请注意,spring 确实会自动检测您的事务管理器,如果您只将其命名为 transactionManager。但就我而言,我有多个这样的 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
}
}
我有一些旧代码需要重构,其中包含 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;
}
我试过了,它确实适用于注释。但是,有几点需要注意:
首先,是在您的配置中使用 @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)。因此,需要在一个事务中的逻辑需要移动到另一个 class 以便它可以被代理。请注意,spring 确实会自动检测您的事务管理器,如果您只将其命名为 transactionManager。但就我而言,我有多个这样的 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
}
}