让Spring+WAS+AspectJ注解事务支持REQUIRES_NEW

[b][size=large]问题描述[/size][/b]
今天发现Spring一个问题
在Spring 2.5.6.SEC01、WebSphere 6.1.0.21、aspectj 1.6.4环境下使用注解@Transactional(propagation=Propagation.REQUIRES_NEW) 开启事务竟然 throw TransactionSuspensionNotSupportedException
官方文档写的很清楚,
[url]http://static.springframework.org/spring/docs/2.5.x/reference/transaction.html#transaction-application-server-integration-websphere[/url]
原文如下:
[b]9.8.1. IBM WebSphere[/b]
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");
}



[b][size=large]解决方案[/size][/b]
使用@Around作为Advice
具体步骤如下
[b]1. 创建@Pointcut[/b]
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.AchievoAbstractTransactionAspect;


/*
* @author xhm(hyamine)
* change the aspectj code style class :org.springframework.transaction.aspectj.AnnotationTransactionAspect
* to @AspectJ style
* Fixed Spring' bug:
* when use @Transactional(propagation=Propagation.REQUIRES_NEW)
in WebSphere 6.1 as AspectJ mode
* will throw TransactionSuspensionNotSupportedException
* because it didn't use WebSphereUowTransactionManager as a CallbackPreferringPlatformTransactionManager
*/

@Aspect
public class AchievoTransactionAspect extends AchievoAbstractTransactionAspect implements Ordered {
private int order = 200;
public AchievoTransactionAspect() {
super(new AnnotationTransactionAttributeSource(false));
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}

@Pointcut("execution(public * ((@org.springframework.transaction.annotation.Transactional *)+).*(..)) && @this(org.springframework.transaction.annotation.Transactional)")
public void executionOfAnyPublicMethodInAtTransactionalType(){}

@Pointcut("execution(* *(..)) && @annotation(org.springframework.transaction.annotation.Transactional)")
public void executionOfTransactionalMethod(){}


@Pointcut("(executionOfAnyPublicMethodInAtTransactionalType() || executionOfTransactionalMethod()) && this(txObject)")
public void transactionalMethodExecution(Object txObject){}

//@SuppressAjWarnings("adviceDidNotMatch")


}

[b]2. 创建@Around advice[/b]
AchievoAbstractTransactionAspect.java
package org.springframework.transaction.interceptor;

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttributeSource;
import org.springframework.transaction.support.CallbackPreferringPlatformTransactionManager;
import org.springframework.transaction.support.TransactionCallback;

/*
* @author xhm(hyamine)
* most of this class code copy from
* org.springframework.transaction.interceptor.TransactionInterceptor
*/

@Aspect
public abstract class AchievoAbstractTransactionAspect extends TransactionAspectSupport {
protected AchievoAbstractTransactionAspect(TransactionAttributeSource tas) {
setTransactionAttributeSource(tas);
}

@Around("transactionalMethodExecution(txObject)")
public Object useTransaction(ProceedingJoinPoint thisJoinPoint,Object txObject) throws Throwable{
Object result = null;
Class targetClass = txObject.getClass();
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
Method method = methodSignature.getMethod();
final TransactionAttribute txAttr =
getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
final String joinpointIdentification = methodIdentification(method);
final ProceedingJoinPoint invocation = thisJoinPoint;
if (txAttr == null || !(getTransactionManager() instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(txAttr, joinpointIdentification);
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
retVal = invocation.proceed();
}
catch (Throwable ex) {
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);
return retVal;
}

else {
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
result = ((CallbackPreferringPlatformTransactionManager) getTransactionManager()).execute(txAttr,
new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
TransactionInfo txInfo = prepareTransactionInfo(txAttr, joinpointIdentification, status);
try {
return invocation.proceed();
}
catch (Throwable ex) {
if (txAttr.rollbackOn(ex)) {
// A RuntimeException: will lead to a rollback.
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
else {
throw new ThrowableHolderException(ex);
}
}
else {
// A normal return value: will lead to a commit.
return new ThrowableHolder(ex);
}
}
finally {
cleanupTransactionInfo(txInfo);
}
}
});

// Check result: It might indicate a Throwable to rethrow.
if (result instanceof ThrowableHolder) {
throw ((ThrowableHolder) result).getThrowable();
}
else {
return result;
}
}
catch (ThrowableHolderException ex) {
throw ex.getCause();
}
}
// result = thisJoinPoint.proceed();
// return result;
}
@Pointcut
public abstract void transactionalMethodExecution(Object txObject);

private static class ThrowableHolder {

private final Throwable throwable;

public ThrowableHolder(Throwable throwable) {
this.throwable = throwable;
}

public final Throwable getThrowable() {
return this.throwable;
}
}
private static class ThrowableHolderException extends RuntimeException {

public ThrowableHolderException(Throwable throwable) {
super(throwable);
}

public String toString() {
return getCause().toString();
}
}
}



[b]3. 修改Aspectj配置文件META-INF/aop.xml(classpath下)[/b]

	<aspects>
<aspect name="com.achievo.framework.transaction.aspectj.AchievoTransactionAspect"/>
<!-- <aspect name="org.springframework.transaction.aspectj.AnnotationTransactionAspect"/> -->
</aspects>


[b]4. 修改spring 配置文件[/b]
<!-- 
<tx:annotation-driven transaction-manager="transactionManager" mode="aspectj" order="100"/>
-->
<bean id="achievoTransaction" class="com.achievo.framework.transaction.aspectj.AchievoTransactionAspect" factory-method="aspectOf">
<property name="transactionManager" ref="transactionManager" />
<property name="order" value="100"/>
</bean>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值