@Transactional in AspectJ mode works with CallbackPreferringPlatformTransactionManager (WebSphere) as well
Effectively, AbstractTransactionAspect got refactored into around advice, reusing former TransactionInterceptor code which now lives in slightly generalized form in TransactionAspectSupport, and using a workaround for rethrowing checked exceptions. Issue: SPR-9268
This commit is contained in:
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.transaction.aspectj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.aspectj.lang.annotation.SuppressAjWarnings;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
||||
@@ -42,45 +40,42 @@ import org.springframework.transaction.interceptor.TransactionAttributeSource;
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract aspect AbstractTransactionAspect extends TransactionAspectSupport {
|
||||
|
||||
/**
|
||||
* Construct object using the given transaction metadata retrieval strategy.
|
||||
* Construct the aspect using the given transaction metadata retrieval strategy.
|
||||
* @param tas TransactionAttributeSource implementation, retrieving Spring
|
||||
* transaction metadata for each joinpoint. Write the subclass to pass in null
|
||||
* if it's intended to be configured by Setter Injection.
|
||||
* transaction metadata for each joinpoint. Implement the subclass to pass in
|
||||
* {@code null} if it is intended to be configured through Setter Injection.
|
||||
*/
|
||||
protected AbstractTransactionAspect(TransactionAttributeSource tas) {
|
||||
setTransactionAttributeSource(tas);
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
before(Object txObject) : transactionalMethodExecution(txObject) {
|
||||
Object around(final Object txObject): transactionalMethodExecution(txObject) {
|
||||
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
|
||||
Method method = methodSignature.getMethod();
|
||||
createTransactionIfNecessary(method, txObject.getClass());
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object txObject) throwing(Throwable t) : transactionalMethodExecution(txObject) {
|
||||
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
|
||||
try {
|
||||
completeTransactionAfterThrowing(TransactionAspectSupport.currentTransactionInfo(), t);
|
||||
return invokeWithinTransaction(methodSignature.getMethod(), txObject.getClass(), new InvocationCallback() {
|
||||
public Object proceedWithInvocation() throws Throwable {
|
||||
return proceed(txObject);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Throwable t2) {
|
||||
logger.error("Failed to close transaction after throwing in a transactional method", t2);
|
||||
catch (RuntimeException ex) {
|
||||
throw ex;
|
||||
}
|
||||
catch (Error err) {
|
||||
throw err;
|
||||
}
|
||||
catch (Throwable thr) {
|
||||
Rethrower.rethrow(thr);
|
||||
throw new IllegalStateException("Should never get here", thr);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object txObject) returning() : transactionalMethodExecution(txObject) {
|
||||
commitTransactionAfterReturning(TransactionAspectSupport.currentTransactionInfo());
|
||||
}
|
||||
|
||||
@SuppressAjWarnings("adviceDidNotMatch")
|
||||
after(Object txObject) : transactionalMethodExecution(txObject) {
|
||||
cleanupTransactionInfo(TransactionAspectSupport.currentTransactionInfo());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,4 +85,22 @@ public abstract aspect AbstractTransactionAspect extends TransactionAspectSuppor
|
||||
*/
|
||||
protected abstract pointcut transactionalMethodExecution(Object txObject);
|
||||
|
||||
|
||||
/**
|
||||
* Ugly but safe workaround: We need to be able to propagate checked exceptions,
|
||||
* despite AspectJ around advice supporting specifically declared exceptions only.
|
||||
*/
|
||||
private static class Rethrower {
|
||||
|
||||
public static void rethrow(final Throwable exception) {
|
||||
class CheckedExceptionRethrower<T extends Throwable> {
|
||||
@SuppressWarnings("unchecked")
|
||||
private void rethrow(Throwable exception) throws T {
|
||||
throw (T) exception;
|
||||
}
|
||||
}
|
||||
new CheckedExceptionRethrower<RuntimeException>().rethrow(exception);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -49,16 +49,14 @@ public aspect AnnotationTransactionAspect extends AbstractTransactionAspect {
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the execution of any public method in a type with the
|
||||
* Transactional annotation, or any subtype of a type with the
|
||||
* Transactional annotation.
|
||||
* Matches the execution of any public method in a type with the Transactional
|
||||
* annotation, or any subtype of a type with the Transactional annotation.
|
||||
*/
|
||||
private pointcut executionOfAnyPublicMethodInAtTransactionalType() :
|
||||
execution(public * ((@Transactional *)+).*(..)) && within(@Transactional *);
|
||||
|
||||
/**
|
||||
* Matches the execution of any method with the
|
||||
* Transactional annotation.
|
||||
* Matches the execution of any method with the Transactional annotation.
|
||||
*/
|
||||
private pointcut executionOfTransactionalMethod() :
|
||||
execution(@Transactional * *(..));
|
||||
|
||||
Reference in New Issue
Block a user