日期:2014-05-17  浏览次数:21226 次

让Spring+WAS+AspectJ注解事务支持REQUIRES_NEW
问题描述
今天发现Spring一个问题
在Spring 2.5.6.SEC01、WebSphere 6.1.0.21、aspectj 1.6.4环境下使用注解@Transactional(propagation=Propagation.REQUIRES_NEW) 开启事务竟然 throw TransactionSuspensionNotSupportedException
官方文档写的很清楚,
http://static.springframework.org/spring/docs/2.5.x/reference/transaction.html#transaction-application-server-integration-websphere
原文如下:
9.8.1. IBM WebSphere
On WebSphere 6.0 and above, the recommended Spring JTA transaction manager to use is WebSphereUowTransactionManager. This special adapter leverages IBM's UOWManager API which is available in WebSphere Application Server 6.0.2.19 or above and 6.1.0.9 or above. With this adapter, Spring-driven transaction suspension (suspend/resume as initiated by PROPAGATION_REQUIRES_NEW) is officially supported by IBM!

从上文来看,很明显是支持的,并且使用配置式事务:
<tx:advice id="txAdvice" transaction-manager="txManager">
		<tx:attributes>
		  <tx:method name="execute" propagation="REQUIRES_NEW"/>
		  <tx:method name="*" read-only="true"/>
		</tx:attributes>
	</tx:advice>

确实是没有问题的,REQUIRES_NEW被支持
究其原因,原来是 AbstractTransactionAspect.java 如下代码导致
@SuppressAjWarnings("adviceDidNotMatch")
	before(Object txObject) { transactionalMethodExecution(txObject)  
		MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
		Method method = methodSignature.getMethod();
		TransactionInfo txInfo = createTransactionIfNecessary(method, txObject.getClass());
	}


TransactionAspectSupport.java
protected TransactionInfo createTransactionIfNecessary(
			TransactionAttribute txAttr, final String joinpointIdentification) {

		// If no name specified, apply method identification as transaction name.
		if (txAttr != null && txAttr.getName() == null) {
			txAttr = new DelegatingTransactionAttribute(txAttr) {
				public String getName() {
					return joinpointIdentification;
				}
			};
		}

		TransactionStatus status = null;
		if (txAttr != null) {
			PlatformTransactionManager tm = getTransactionManager();
			if (tm != null) {
				status = tm.getTransaction(txAttr);
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
							"] because no transaction manager has been configured");
				}
			}
		}
		return prepareTransactionInfo(txAttr, joinpointIdentification, status);
	}


由于使用的是
是@Before、@AfterReturning 、@AfterThrowing这些Advice来开启、提交、回滚事务
而不是@Around,
没有把 WebSphereUowTransactionManager 作为CallbackPreferringPlatformTransactionManager使用
(未用WebSphereUowTransactionManager.execute进行回调)
从而导致IBM的UOWManager接口根本就没有使用到,
并且WebSphere是不提供javax.transaction.TransactionManager给用户的,
当Spring执行到
org.springframework.transaction.jta.JtaTransactionManager.doJtaResume
时发现getTransactionManager() == null
if (getTransactionManager() == null) {
			throw new TransactionSuspensionNotSupportedException(
					"JtaTransactionManager needs a JTA TransactionManager for suspending a transaction: " +
					"specify the 'transactionManager' or 'transactionManagerName' property");
		}



解决方案
使用@Around作为Advice
具体步骤如下
1. 创建@Pointcut
AchievoTransactionAspect.java
package com.achievo.framework.transaction.aspectj;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.Ordered;
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
import org.springframework.transaction.interceptor.AchievoAbstractTransactionA