@Transactional supports qualifier value for choosing between multiple transaction managers
This commit is contained in:
parent
dc83107d66
commit
d34c4a2cf0
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -18,12 +18,11 @@ package org.springframework.transaction.annotation;
|
|||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
|
||||
import javax.ejb.ApplicationException;
|
||||
import javax.ejb.TransactionAttributeType;
|
||||
|
||||
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
|
||||
import org.springframework.transaction.interceptor.TransactionAttribute;
|
||||
import org.springframework.transaction.support.DefaultTransactionDefinition;
|
||||
|
||||
/**
|
||||
* Strategy implementation for parsing EJB3's {@link javax.ejb.TransactionAttribute}
|
||||
|
|
@ -53,8 +52,7 @@ public class Ejb3TransactionAnnotationParser implements TransactionAnnotationPar
|
|||
* EJB3-specific TransactionAttribute, implementing EJB3's rollback rules
|
||||
* which are based on annotated exceptions.
|
||||
*/
|
||||
private static class Ejb3TransactionAttribute extends DefaultTransactionDefinition
|
||||
implements TransactionAttribute {
|
||||
private static class Ejb3TransactionAttribute extends DefaultTransactionAttribute {
|
||||
|
||||
public Ejb3TransactionAttribute(TransactionAttributeType type) {
|
||||
setPropagationBehaviorName(PREFIX_PROPAGATION + type.name());
|
||||
|
|
@ -62,7 +60,7 @@ public class Ejb3TransactionAnnotationParser implements TransactionAnnotationPar
|
|||
|
||||
public boolean rollbackOn(Throwable ex) {
|
||||
ApplicationException ann = ex.getClass().getAnnotation(ApplicationException.class);
|
||||
return (ann != null ? ann.rollback() : (ex instanceof RuntimeException || ex instanceof Error));
|
||||
return (ann != null ? ann.rollback() : super.rollbackOn(ex));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
package org.springframework.transaction.annotation;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.springframework.transaction.interceptor.NoRollbackRuleAttribute;
|
||||
|
|
@ -58,6 +58,7 @@ public class SpringTransactionAnnotationParser implements TransactionAnnotationP
|
|||
rbta.setIsolationLevel(ann.isolation().value());
|
||||
rbta.setTimeout(ann.timeout());
|
||||
rbta.setReadOnly(ann.readOnly());
|
||||
rbta.setQualifier(ann.value());
|
||||
ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<RollbackRuleAttribute>();
|
||||
Class[] rbf = ann.rollbackFor();
|
||||
for (Class rbRule : rbf) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -49,6 +49,15 @@ import org.springframework.transaction.TransactionDefinition;
|
|||
@Documented
|
||||
public @interface Transactional {
|
||||
|
||||
/**
|
||||
* A qualifier value for the specified transaction.
|
||||
* <p>May be used to determine the target transaction manager,
|
||||
* matching the qualifier value (or the bean name) of a specific
|
||||
* {@link org.springframework.transaction.PlatformTransactionManager}
|
||||
* bean definition.
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
/**
|
||||
* The transaction propagation type.
|
||||
* <p>Defaults to {@link Propagation#REQUIRED}.
|
||||
|
|
|
|||
|
|
@ -95,8 +95,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
|||
private static void registerTransactionManager(Element element, BeanDefinition def) {
|
||||
String transactionManagerName = (element.hasAttribute(TxNamespaceUtils.TRANSACTION_MANAGER_ATTRIBUTE) ?
|
||||
element.getAttribute(TxNamespaceUtils.TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);
|
||||
def.getPropertyValues().addPropertyValue(
|
||||
TxNamespaceUtils.TRANSACTION_MANAGER_PROPERTY, new RuntimeBeanReference(transactionManagerName));
|
||||
def.getPropertyValues().addPropertyValue("transactionManagerBeanName", transactionManagerName);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ import org.springframework.transaction.support.DefaultTransactionDefinition;
|
|||
*/
|
||||
public class DefaultTransactionAttribute extends DefaultTransactionDefinition implements TransactionAttribute {
|
||||
|
||||
private String qualifier;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new DefaultTransactionAttribute, with default settings.
|
||||
* Can be modified through bean property setters.
|
||||
|
|
@ -66,10 +69,18 @@ public class DefaultTransactionAttribute extends DefaultTransactionDefinition im
|
|||
}
|
||||
|
||||
|
||||
public void setQualifier(String qualifier) {
|
||||
this.qualifier = qualifier;
|
||||
}
|
||||
|
||||
public String getQualifier() {
|
||||
return this.qualifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default behavior is as with EJB: rollback on unchecked exception.
|
||||
* The default behavior is as with EJB: rollback on unchecked exception.
|
||||
* Additionally attempt to rollback on Error.
|
||||
* Consistent with TransactionTemplate's behavior.
|
||||
* <p>This is consistent with TransactionTemplate's default behavior.
|
||||
*/
|
||||
public boolean rollbackOn(Throwable ex) {
|
||||
return (ex instanceof RuntimeException || ex instanceof Error);
|
||||
|
|
|
|||
|
|
@ -64,6 +64,10 @@ public abstract class DelegatingTransactionAttribute implements TransactionAttri
|
|||
return this.targetAttribute.getName();
|
||||
}
|
||||
|
||||
public String getQualifier() {
|
||||
return this.targetAttribute.getQualifier();
|
||||
}
|
||||
|
||||
public boolean rollbackOn(Throwable ex) {
|
||||
return this.targetAttribute.rollbackOn(ex);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,18 +17,30 @@
|
|||
package org.springframework.transaction.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
|
||||
import org.springframework.core.NamedThreadLocal;
|
||||
import org.springframework.transaction.NoTransactionException;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.TransactionSystemException;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Base class for transactional aspects, such as the AOP Alliance
|
||||
|
|
@ -61,7 +73,7 @@ import org.springframework.util.ClassUtils;
|
|||
* @see #setTransactionAttributes
|
||||
* @see #setTransactionAttributeSource
|
||||
*/
|
||||
public abstract class TransactionAspectSupport implements InitializingBean {
|
||||
public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
|
||||
|
||||
// NOTE: This class must not implement Serializable because it serves as base
|
||||
// class for AspectJ aspects (which are not allowed to implement Serializable)!
|
||||
|
|
@ -94,8 +106,9 @@ public abstract class TransactionAspectSupport implements InitializingBean {
|
|||
* @see org.springframework.transaction.support.TransactionSynchronizationManager#isActualTransactionActive()
|
||||
*/
|
||||
protected static TransactionInfo currentTransactionInfo() throws NoTransactionException {
|
||||
return (TransactionInfo) transactionInfoHolder.get();
|
||||
return transactionInfoHolder.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transaction status of the current method invocation.
|
||||
* Mainly intended for code that wants to set the current transaction
|
||||
|
|
@ -114,23 +127,31 @@ public abstract class TransactionAspectSupport implements InitializingBean {
|
|||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
/** Delegate used to create, commit and rollback transactions */
|
||||
private String transactionManagerBeanName;
|
||||
|
||||
private PlatformTransactionManager transactionManager;
|
||||
|
||||
/** Helper used to find transaction attributes */
|
||||
private TransactionAttributeSource transactionAttributeSource;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Set the transaction manager. This will perform actual
|
||||
* transaction management: This class is just a way of invoking it.
|
||||
* Specify the name of the default transaction manager bean.
|
||||
*/
|
||||
public void setTransactionManagerBeanName(String transactionManagerBeanName) {
|
||||
this.transactionManagerBeanName = transactionManagerBeanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the target transaction manager.
|
||||
*/
|
||||
public void setTransactionManager(PlatformTransactionManager transactionManager) {
|
||||
this.transactionManager = transactionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transaction manager.
|
||||
* Return the transaction manager, if specified.
|
||||
*/
|
||||
public PlatformTransactionManager getTransactionManager() {
|
||||
return this.transactionManager;
|
||||
|
|
@ -160,7 +181,6 @@ public abstract class TransactionAspectSupport implements InitializingBean {
|
|||
* @see CompositeTransactionAttributeSource
|
||||
* @see MethodMapTransactionAttributeSource
|
||||
* @see NameMatchTransactionAttributeSource
|
||||
* @see AttributesTransactionAttributeSource
|
||||
* @see org.springframework.transaction.annotation.AnnotationTransactionAttributeSource
|
||||
*/
|
||||
public void setTransactionAttributeSources(TransactionAttributeSource[] transactionAttributeSources) {
|
||||
|
|
@ -174,7 +194,6 @@ public abstract class TransactionAspectSupport implements InitializingBean {
|
|||
* @see TransactionAttributeSourceEditor
|
||||
* @see MethodMapTransactionAttributeSource
|
||||
* @see NameMatchTransactionAttributeSource
|
||||
* @see AttributesTransactionAttributeSource
|
||||
* @see org.springframework.transaction.annotation.AnnotationTransactionAttributeSource
|
||||
*/
|
||||
public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
|
||||
|
|
@ -188,22 +207,79 @@ public abstract class TransactionAspectSupport implements InitializingBean {
|
|||
return this.transactionAttributeSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the BeanFactory to use for retrieving PlatformTransactionManager beans.
|
||||
*/
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that required properties were set.
|
||||
*/
|
||||
public void afterPropertiesSet() {
|
||||
if (getTransactionManager() == null) {
|
||||
throw new IllegalArgumentException("Property 'transactionManager' is required");
|
||||
if (this.transactionManager == null && this.beanFactory == null) {
|
||||
throw new IllegalStateException(
|
||||
"Setting the property 'transactionManager' or running in a ListableBeanFactory is required");
|
||||
}
|
||||
if (getTransactionAttributeSource() == null) {
|
||||
throw new IllegalArgumentException(
|
||||
if (this.transactionAttributeSource == null) {
|
||||
throw new IllegalStateException(
|
||||
"Either 'transactionAttributeSource' or 'transactionAttributes' is required: " +
|
||||
"If there are no transactional methods, then don't use a transaction aspect.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine the specific transaction manager to use for the given transaction.
|
||||
*/
|
||||
protected PlatformTransactionManager determineTransactionManager(TransactionAttribute txAttr) {
|
||||
if (this.transactionManager != null) {
|
||||
return this.transactionManager;
|
||||
}
|
||||
PlatformTransactionManager chosen = null;
|
||||
String qualifier = txAttr.getQualifier();
|
||||
if (StringUtils.hasLength(qualifier)) {
|
||||
if (!(this.beanFactory instanceof ConfigurableListableBeanFactory)) {
|
||||
throw new IllegalStateException("BeanFactory required to be a ConfigurableListableBeanFactory " +
|
||||
"for resolution of qualifier '" + qualifier + "': " + this.beanFactory.getClass());
|
||||
}
|
||||
ConfigurableListableBeanFactory bf = (ConfigurableListableBeanFactory) this.beanFactory;
|
||||
Map<String, PlatformTransactionManager> tms =
|
||||
BeanFactoryUtils.beansOfTypeIncludingAncestors(bf, PlatformTransactionManager.class);
|
||||
for (String beanName : tms.keySet()) {
|
||||
if (bf.containsBeanDefinition(beanName)) {
|
||||
BeanDefinition bd = bf.getBeanDefinition(beanName);
|
||||
if (bd instanceof AbstractBeanDefinition) {
|
||||
AbstractBeanDefinition abd = (AbstractBeanDefinition) bd;
|
||||
AutowireCandidateQualifier candidate = abd.getQualifier(Qualifier.class.getName());
|
||||
if ((candidate != null && qualifier.equals(candidate.getAttribute(AutowireCandidateQualifier.VALUE_KEY))) ||
|
||||
qualifier.equals(beanName) || ObjectUtils.containsElement(bf.getAliases(beanName), qualifier)) {
|
||||
if (chosen != null) {
|
||||
throw new IllegalStateException("No unique PlatformTransactionManager bean found " +
|
||||
"for qualifier '" + qualifier + "'");
|
||||
}
|
||||
chosen = tms.get(beanName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chosen != null) {
|
||||
return chosen;
|
||||
}
|
||||
else if (this.transactionManagerBeanName != null) {
|
||||
return this.beanFactory.getBean(this.transactionManagerBeanName, PlatformTransactionManager.class);
|
||||
}
|
||||
else if (this.beanFactory instanceof ListableBeanFactory) {
|
||||
return BeanFactoryUtils.beanOfTypeIncludingAncestors(((ListableBeanFactory) this.beanFactory), PlatformTransactionManager.class);
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException(
|
||||
"Cannot retrieve PlatformTransactionManager beans from non-listable BeanFactory: " + this.beanFactory);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a transaction if necessary, based on the given method and class.
|
||||
* <p>Performs a default TransactionAttribute lookup for the given method.
|
||||
|
|
@ -217,7 +293,8 @@ public abstract class TransactionAspectSupport implements InitializingBean {
|
|||
protected TransactionInfo createTransactionIfNecessary(Method method, Class targetClass) {
|
||||
// If the transaction attribute is null, the method is non-transactional.
|
||||
TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
|
||||
return createTransactionIfNecessary(txAttr, methodIdentification(method));
|
||||
PlatformTransactionManager tm = determineTransactionManager(txAttr);
|
||||
return createTransactionIfNecessary(tm, txAttr, methodIdentification(method));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -245,7 +322,7 @@ public abstract class TransactionAspectSupport implements InitializingBean {
|
|||
* @see #getTransactionAttributeSource()
|
||||
*/
|
||||
protected TransactionInfo createTransactionIfNecessary(
|
||||
TransactionAttribute txAttr, final String joinpointIdentification) {
|
||||
PlatformTransactionManager tm, TransactionAttribute txAttr, final String joinpointIdentification) {
|
||||
|
||||
// If no name specified, apply method identification as transaction name.
|
||||
if (txAttr != null && txAttr.getName() == null) {
|
||||
|
|
@ -259,7 +336,6 @@ public abstract class TransactionAspectSupport implements InitializingBean {
|
|||
|
||||
TransactionStatus status = null;
|
||||
if (txAttr != null) {
|
||||
PlatformTransactionManager tm = getTransactionManager();
|
||||
if (tm != null) {
|
||||
status = tm.getTransaction(txAttr);
|
||||
}
|
||||
|
|
@ -270,7 +346,7 @@ public abstract class TransactionAspectSupport implements InitializingBean {
|
|||
}
|
||||
}
|
||||
}
|
||||
return prepareTransactionInfo(txAttr, joinpointIdentification, status);
|
||||
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -281,10 +357,10 @@ public abstract class TransactionAspectSupport implements InitializingBean {
|
|||
* @param status the TransactionStatus for the current transaction
|
||||
* @return the prepared TransactionInfo object
|
||||
*/
|
||||
protected TransactionInfo prepareTransactionInfo(
|
||||
protected TransactionInfo prepareTransactionInfo(PlatformTransactionManager tm,
|
||||
TransactionAttribute txAttr, String joinpointIdentification, TransactionStatus status) {
|
||||
|
||||
TransactionInfo txInfo = new TransactionInfo(txAttr, joinpointIdentification);
|
||||
TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
|
||||
if (txAttr != null) {
|
||||
// We need a transaction for this method
|
||||
if (logger.isTraceEnabled()) {
|
||||
|
|
@ -319,7 +395,7 @@ public abstract class TransactionAspectSupport implements InitializingBean {
|
|||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
|
||||
}
|
||||
getTransactionManager().commit(txInfo.getTransactionStatus());
|
||||
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -337,7 +413,7 @@ public abstract class TransactionAspectSupport implements InitializingBean {
|
|||
}
|
||||
if (txInfo.transactionAttribute.rollbackOn(ex)) {
|
||||
try {
|
||||
getTransactionManager().rollback(txInfo.getTransactionStatus());
|
||||
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
|
||||
}
|
||||
catch (TransactionSystemException ex2) {
|
||||
logger.error("Application exception overridden by rollback exception", ex);
|
||||
|
|
@ -357,7 +433,7 @@ public abstract class TransactionAspectSupport implements InitializingBean {
|
|||
// We don't roll back on this exception.
|
||||
// Will still roll back if TransactionStatus.isRollbackOnly() is true.
|
||||
try {
|
||||
getTransactionManager().commit(txInfo.getTransactionStatus());
|
||||
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
|
||||
}
|
||||
catch (TransactionSystemException ex2) {
|
||||
logger.error("Application exception overridden by commit exception", ex);
|
||||
|
|
@ -392,7 +468,9 @@ public abstract class TransactionAspectSupport implements InitializingBean {
|
|||
* Opaque object used to hold Transaction information. Subclasses
|
||||
* must pass it back to methods on this class, but not see its internals.
|
||||
*/
|
||||
protected class TransactionInfo {
|
||||
protected final class TransactionInfo {
|
||||
|
||||
private final PlatformTransactionManager transactionManager;
|
||||
|
||||
private final TransactionAttribute transactionAttribute;
|
||||
|
||||
|
|
@ -402,11 +480,17 @@ public abstract class TransactionAspectSupport implements InitializingBean {
|
|||
|
||||
private TransactionInfo oldTransactionInfo;
|
||||
|
||||
public TransactionInfo(TransactionAttribute transactionAttribute, String joinpointIdentification) {
|
||||
public TransactionInfo(PlatformTransactionManager transactionManager,
|
||||
TransactionAttribute transactionAttribute, String joinpointIdentification) {
|
||||
this.transactionManager = transactionManager;
|
||||
this.transactionAttribute = transactionAttribute;
|
||||
this.joinpointIdentification = joinpointIdentification;
|
||||
}
|
||||
|
||||
public PlatformTransactionManager getTransactionManager() {
|
||||
return this.transactionManager;
|
||||
}
|
||||
|
||||
public TransactionAttribute getTransactionAttribute() {
|
||||
return this.transactionAttribute;
|
||||
}
|
||||
|
|
@ -438,7 +522,7 @@ public abstract class TransactionAspectSupport implements InitializingBean {
|
|||
private void bindToThread() {
|
||||
// Expose current TransactionStatus, preserving any existing TransactionStatus
|
||||
// for restoration after this transaction is complete.
|
||||
this.oldTransactionInfo = (TransactionInfo) transactionInfoHolder.get();
|
||||
this.oldTransactionInfo = transactionInfoHolder.get();
|
||||
transactionInfoHolder.set(this);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
|
@ -19,7 +19,7 @@ package org.springframework.transaction.interceptor;
|
|||
import org.springframework.transaction.TransactionDefinition;
|
||||
|
||||
/**
|
||||
* This interface adds a <code>rollbackOn</code> specification to TransactionDefinition.
|
||||
* This interface adds a <code>rollbackOn</code> specification to {@link TransactionDefinition}.
|
||||
* As custom <code>rollbackOn</code> is only possible with AOP, this class resides
|
||||
* in the AOP transaction package.
|
||||
*
|
||||
|
|
@ -29,7 +29,9 @@ import org.springframework.transaction.TransactionDefinition;
|
|||
* @see RuleBasedTransactionAttribute
|
||||
*/
|
||||
public interface TransactionAttribute extends TransactionDefinition {
|
||||
|
||||
|
||||
String getQualifier();
|
||||
|
||||
/**
|
||||
* Should we roll back on the given exception?
|
||||
* @param ex the exception to evaluate
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -94,11 +94,12 @@ public class TransactionInterceptor extends TransactionAspectSupport implements
|
|||
// If the transaction attribute is null, the method is non-transactional.
|
||||
final TransactionAttribute txAttr =
|
||||
getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);
|
||||
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
|
||||
final String joinpointIdentification = methodIdentification(invocation.getMethod());
|
||||
|
||||
if (txAttr == null || !(getTransactionManager() instanceof CallbackPreferringPlatformTransactionManager)) {
|
||||
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
|
||||
// Standard transaction demarcation with getTransaction and commit/rollback calls.
|
||||
TransactionInfo txInfo = createTransactionIfNecessary(txAttr, joinpointIdentification);
|
||||
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
|
||||
Object retVal = null;
|
||||
try {
|
||||
// This is an around advice: Invoke the next interceptor in the chain.
|
||||
|
|
@ -120,10 +121,10 @@ public class TransactionInterceptor extends TransactionAspectSupport implements
|
|||
else {
|
||||
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
|
||||
try {
|
||||
Object result = ((CallbackPreferringPlatformTransactionManager) getTransactionManager()).execute(txAttr,
|
||||
new TransactionCallback() {
|
||||
Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
|
||||
new TransactionCallback<Object>() {
|
||||
public Object doInTransaction(TransactionStatus status) {
|
||||
TransactionInfo txInfo = prepareTransactionInfo(txAttr, joinpointIdentification, status);
|
||||
TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
|
||||
try {
|
||||
return invocation.proceed();
|
||||
}
|
||||
|
|
@ -167,6 +168,15 @@ public class TransactionInterceptor extends TransactionAspectSupport implements
|
|||
// Serialization support
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
private void writeObject(ObjectOutputStream oos) throws IOException {
|
||||
// Rely on default serialization, although this class itself doesn't carry state anyway...
|
||||
oos.defaultWriteObject();
|
||||
|
||||
// Deserialize superclass fields.
|
||||
oos.writeObject(getTransactionManager());
|
||||
oos.writeObject(getTransactionAttributeSource());
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
|
||||
// Rely on default serialization, although this class itself doesn't carry state anyway...
|
||||
ois.defaultReadObject();
|
||||
|
|
@ -178,15 +188,6 @@ public class TransactionInterceptor extends TransactionAspectSupport implements
|
|||
setTransactionAttributeSource((TransactionAttributeSource) ois.readObject());
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream oos) throws IOException {
|
||||
// Rely on default serialization, although this class itself doesn't carry state anyway...
|
||||
oos.defaultWriteObject();
|
||||
|
||||
// Deserialize superclass fields.
|
||||
oos.writeObject(getTransactionManager());
|
||||
oos.writeObject(getTransactionAttributeSource());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Internal holder class for a Throwable, used as a return value
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import org.springframework.aop.framework.AbstractSingletonProxyFactoryBean;
|
|||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
|
@ -171,12 +170,7 @@ public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBe
|
|||
* @see org.springframework.transaction.PlatformTransactionManager
|
||||
*/
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
if (this.transactionInterceptor.getTransactionManager() == null &&
|
||||
beanFactory instanceof ListableBeanFactory) {
|
||||
ListableBeanFactory lbf = (ListableBeanFactory) beanFactory;
|
||||
PlatformTransactionManager ptm = BeanFactoryUtils.beanOfTypeIncludingAncestors(lbf, PlatformTransactionManager.class);
|
||||
this.transactionInterceptor.setTransactionManager(ptm);
|
||||
}
|
||||
this.transactionInterceptor.setBeanFactory(beanFactory);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import org.aopalliance.intercept.MethodInvocation;
|
|||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.transaction.CallCountingTransactionManager;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
/**
|
||||
|
|
@ -32,16 +33,34 @@ public class AnnotationDrivenTests extends TestCase {
|
|||
|
||||
public void testWithProxyTargetClass() throws Exception {
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("annotationDrivenProxyTargetClassTests.xml", getClass());
|
||||
TransactionalService service = (TransactionalService) context.getBean("service");
|
||||
CallCountingTransactionManager tm1 = context.getBean("transactionManager1", CallCountingTransactionManager.class);
|
||||
CallCountingTransactionManager tm2 = context.getBean("transactionManager2", CallCountingTransactionManager.class);
|
||||
TransactionalService service = context.getBean("service", TransactionalService.class);
|
||||
assertTrue(AopUtils.isCglibProxy(service));
|
||||
service.setBeanName("someName");
|
||||
service.setSomething("someName");
|
||||
assertEquals(1, tm1.commits);
|
||||
assertEquals(0, tm2.commits);
|
||||
service.doSomething();
|
||||
assertEquals(1, tm1.commits);
|
||||
assertEquals(1, tm2.commits);
|
||||
service.setSomething("someName");
|
||||
assertEquals(2, tm1.commits);
|
||||
assertEquals(1, tm2.commits);
|
||||
service.doSomething();
|
||||
assertEquals(2, tm1.commits);
|
||||
assertEquals(2, tm2.commits);
|
||||
}
|
||||
|
||||
|
||||
public static class TransactionCheckingInterceptor implements MethodInterceptor {
|
||||
|
||||
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
|
||||
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
|
||||
if (methodInvocation.getMethod().getName().equals("setSomething")) {
|
||||
assertTrue(TransactionSynchronizationManager.isSynchronizationActive());
|
||||
}
|
||||
else {
|
||||
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
|
||||
}
|
||||
return methodInvocation.proceed();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -21,12 +21,16 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
|
||||
/**
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
@Transactional
|
||||
public class TransactionalService implements BeanNameAware {
|
||||
public class TransactionalService {
|
||||
|
||||
public void setBeanName(String name) {
|
||||
// just for testing :)
|
||||
@Transactional("synch")
|
||||
public void setSomething(String name) {
|
||||
}
|
||||
|
||||
@Transactional("noSynch")
|
||||
public void doSomething() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
|
||||
|
||||
<tx:annotation-driven proxy-target-class="true" order="0"/>
|
||||
|
||||
|
|
@ -12,8 +12,15 @@
|
|||
|
||||
<bean id="txCheckingInterceptor" class="org.springframework.transaction.config.AnnotationDrivenTests$TransactionCheckingInterceptor"/>
|
||||
|
||||
<bean id="transactionManager" class="org.springframework.transaction.CallCountingTransactionManager"/>
|
||||
<bean id="transactionManager1" class="org.springframework.transaction.CallCountingTransactionManager">
|
||||
<qualifier value="synch"/>
|
||||
</bean>
|
||||
|
||||
<bean id="transactionManager2" class="org.springframework.transaction.CallCountingTransactionManager">
|
||||
<property name="transactionSynchronizationName" value="SYNCHRONIZATION_NEVER"/>
|
||||
<qualifier value="noSynch"/>
|
||||
</bean>
|
||||
|
||||
<bean id="service" class="org.springframework.transaction.config.TransactionalService"/>
|
||||
|
||||
</beans>
|
||||
|
|
|
|||
Loading…
Reference in New Issue