提交 52b029d7 编写于 作者: J Juergen Hoeller

DefaultTransactionAttribute stores descriptor (method identification)

Issue: SPR-14760
上级 67a5ff02
...@@ -511,8 +511,21 @@ public abstract class ClassUtils { ...@@ -511,8 +511,21 @@ public abstract class ClassUtils {
* @return the qualified name of the method * @return the qualified name of the method
*/ */
public static String getQualifiedMethodName(Method method) { public static String getQualifiedMethodName(Method method) {
return getQualifiedMethodName(method, null);
}
/**
* Return the qualified name of the given method, consisting of
* fully qualified interface/class name + "." + method name.
* @param method the method
* @param clazz the clazz that the method is being invoked on
* (may be {@code null} to indicate the method's declaring class)
* @return the qualified name of the method
* @since 4.3.4
*/
public static String getQualifiedMethodName(Method method, Class<?> clazz) {
Assert.notNull(method, "Method must not be null"); Assert.notNull(method, "Method must not be null");
return method.getDeclaringClass().getName() + "." + method.getName(); return (clazz != null ? clazz : method.getDeclaringClass()).getName() + '.' + method.getName();
} }
/** /**
...@@ -640,10 +653,10 @@ public abstract class ClassUtils { ...@@ -640,10 +653,10 @@ public abstract class ClassUtils {
return candidates.iterator().next(); return candidates.iterator().next();
} }
else if (candidates.isEmpty()) { else if (candidates.isEmpty()) {
throw new IllegalStateException("Expected method not found: " + clazz + "." + methodName); throw new IllegalStateException("Expected method not found: " + clazz.getName() + '.' + methodName);
} }
else { else {
throw new IllegalStateException("No unique method found: " + clazz + "." + methodName); throw new IllegalStateException("No unique method found: " + clazz.getName() + '.' + methodName);
} }
} }
} }
...@@ -980,7 +993,7 @@ public abstract class ClassUtils { ...@@ -980,7 +993,7 @@ public abstract class ClassUtils {
public static String addResourcePathToPackagePath(Class<?> clazz, String resourceName) { public static String addResourcePathToPackagePath(Class<?> clazz, String resourceName) {
Assert.notNull(resourceName, "Resource name must not be null"); Assert.notNull(resourceName, "Resource name must not be null");
if (!resourceName.startsWith("/")) { if (!resourceName.startsWith("/")) {
return classPackageAsResourcePath(clazz) + "/" + resourceName; return classPackageAsResourcePath(clazz) + '/' + resourceName;
} }
return classPackageAsResourcePath(clazz) + resourceName; return classPackageAsResourcePath(clazz) + resourceName;
} }
......
...@@ -97,20 +97,22 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran ...@@ -97,20 +97,22 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran
} }
else { else {
// We need to work it out. // We need to work it out.
TransactionAttribute txAtt = computeTransactionAttribute(method, targetClass); TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// Put it in the cache. // Put it in the cache.
if (txAtt == null) { if (txAttr == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE); this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
} }
else { else {
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
if (txAttr instanceof DefaultTransactionAttribute) {
((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
}
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
Class<?> classToLog = (targetClass != null ? targetClass : method.getDeclaringClass()); logger.debug("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
logger.debug("Adding transactional method '" + classToLog.getSimpleName() + "." +
method.getName() + "' with attribute: " + txAtt);
} }
this.attributeCache.put(cacheKey, txAtt); this.attributeCache.put(cacheKey, txAttr);
} }
return txAtt; return txAttr;
} }
} }
...@@ -148,27 +150,27 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran ...@@ -148,27 +150,27 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod); specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
// First try is the method in the target class. // First try is the method in the target class.
TransactionAttribute txAtt = findTransactionAttribute(specificMethod); TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAtt != null) { if (txAttr != null) {
return txAtt; return txAttr;
} }
// Second try is the transaction attribute on the target class. // Second try is the transaction attribute on the target class.
txAtt = findTransactionAttribute(specificMethod.getDeclaringClass()); txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAtt != null && ClassUtils.isUserLevelMethod(method)) { if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAtt; return txAttr;
} }
if (specificMethod != method) { if (specificMethod != method) {
// Fallback is to look at the original method. // Fallback is to look at the original method.
txAtt = findTransactionAttribute(method); txAttr = findTransactionAttribute(method);
if (txAtt != null) { if (txAttr != null) {
return txAtt; return txAttr;
} }
// Last fallback is the class of the original method. // Last fallback is the class of the original method.
txAtt = findTransactionAttribute(method.getDeclaringClass()); txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAtt != null && ClassUtils.isUserLevelMethod(method)) { if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAtt; return txAttr;
} }
} }
......
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -19,10 +19,11 @@ package org.springframework.transaction.interceptor; ...@@ -19,10 +19,11 @@ package org.springframework.transaction.interceptor;
import org.springframework.transaction.support.DefaultTransactionDefinition; import org.springframework.transaction.support.DefaultTransactionDefinition;
/** /**
* Transaction attribute that takes the EJB approach to rolling * Spring's common transaction attribute implementation.
* back on runtime, but not checked, exceptions. * Rolls back on runtime, but not checked, exceptions by default.
* *
* @author Rod Johnson * @author Rod Johnson
* @author Juergen Hoeller
* @since 16.03.2003 * @since 16.03.2003
*/ */
@SuppressWarnings("serial") @SuppressWarnings("serial")
...@@ -30,6 +31,8 @@ public class DefaultTransactionAttribute extends DefaultTransactionDefinition im ...@@ -30,6 +31,8 @@ public class DefaultTransactionAttribute extends DefaultTransactionDefinition im
private String qualifier; private String qualifier;
private String descriptor;
/** /**
* Create a new DefaultTransactionAttribute, with default settings. * Create a new DefaultTransactionAttribute, with default settings.
...@@ -74,6 +77,7 @@ public class DefaultTransactionAttribute extends DefaultTransactionDefinition im ...@@ -74,6 +77,7 @@ public class DefaultTransactionAttribute extends DefaultTransactionDefinition im
* Associate a qualifier value with this transaction attribute. * Associate a qualifier value with this transaction attribute.
* <p>This may be used for choosing a corresponding transaction manager * <p>This may be used for choosing a corresponding transaction manager
* to process this specific transaction. * to process this specific transaction.
* @since 3.0
*/ */
public void setQualifier(String qualifier) { public void setQualifier(String qualifier) {
this.qualifier = qualifier; this.qualifier = qualifier;
...@@ -81,12 +85,31 @@ public class DefaultTransactionAttribute extends DefaultTransactionDefinition im ...@@ -81,12 +85,31 @@ public class DefaultTransactionAttribute extends DefaultTransactionDefinition im
/** /**
* Return a qualifier value associated with this transaction attribute. * Return a qualifier value associated with this transaction attribute.
* @since 3.0
*/ */
@Override @Override
public String getQualifier() { public String getQualifier() {
return this.qualifier; return this.qualifier;
} }
/**
* Set a descriptor for this transaction attribute,
* e.g. indicating where the attribute is applying.
* @since 4.3.4
*/
public void setDescriptor(String descriptor) {
this.descriptor = descriptor;
}
/**
* Return a descriptor for this transaction attribute,
* or {@code null} if none.
* @since 4.3.4
*/
public String getDescriptor() {
return this.descriptor;
}
/** /**
* The 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. * Additionally attempt to rollback on Error.
......
...@@ -34,6 +34,7 @@ import org.springframework.transaction.TransactionStatus; ...@@ -34,6 +34,7 @@ import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.TransactionSystemException; import org.springframework.transaction.TransactionSystemException;
import org.springframework.transaction.support.CallbackPreferringPlatformTransactionManager; import org.springframework.transaction.support.CallbackPreferringPlatformTransactionManager;
import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionCallback;
import org.springframework.util.ClassUtils;
import org.springframework.util.ConcurrentReferenceHashMap; import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
...@@ -269,7 +270,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init ...@@ -269,7 +270,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
// If the transaction attribute is null, the method is non-transactional. // If the transaction attribute is null, the method is non-transactional.
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass); final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
final PlatformTransactionManager tm = determineTransactionManager(txAttr); final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass); final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) { if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls. // Standard transaction demarcation with getTransaction and commit/rollback calls.
...@@ -385,17 +386,33 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init ...@@ -385,17 +386,33 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
return txManager; return txManager;
} }
private String methodIdentification(Method method, Class<?> targetClass, TransactionAttribute txAttr) {
String methodIdentification = methodIdentification(method, targetClass);
if (methodIdentification == null) {
if (txAttr instanceof DefaultTransactionAttribute) {
methodIdentification = ((DefaultTransactionAttribute) txAttr).getDescriptor();
}
if (methodIdentification == null) {
methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
}
}
return methodIdentification;
}
/** /**
* Convenience method to return a String representation of this Method * Convenience method to return a String representation of this Method
* for use in logging. Can be overridden in subclasses to provide a * for use in logging. Can be overridden in subclasses to provide a
* different identifier for the given method. * different identifier for the given method.
* <p>The default implementation returns {@code null}, indicating the
* use of {@link DefaultTransactionAttribute#getDescriptor()} instead,
* ending up as {@link ClassUtils#getQualifiedMethodName(Method, Class)}.
* @param method the method we're interested in * @param method the method we're interested in
* @param targetClass the class that the method is being invoked on * @param targetClass the class that the method is being invoked on
* @return a String representation identifying this method * @return a String representation identifying this method
* @see org.springframework.util.ClassUtils#getQualifiedMethodName * @see org.springframework.util.ClassUtils#getQualifiedMethodName
*/ */
protected String methodIdentification(Method method, Class<?> targetClass) { protected String methodIdentification(Method method, Class<?> targetClass) {
return (targetClass != null ? targetClass : method.getDeclaringClass()).getName() + "." + method.getName(); return null;
} }
/** /**
......
...@@ -31,12 +31,12 @@ public class MapTransactionAttributeSource extends AbstractFallbackTransactionAt ...@@ -31,12 +31,12 @@ public class MapTransactionAttributeSource extends AbstractFallbackTransactionAt
private final Map<Object, TransactionAttribute> attributeMap = new HashMap<>(); private final Map<Object, TransactionAttribute> attributeMap = new HashMap<>();
public void register(Method method, TransactionAttribute txAtt) { public void register(Method method, TransactionAttribute txAttr) {
this.attributeMap.put(method, txAtt); this.attributeMap.put(method, txAttr);
} }
public void register(Class<?> clazz, TransactionAttribute txAtt) { public void register(Class<?> clazz, TransactionAttribute txAttr) {
this.attributeMap.put(clazz, txAtt); this.attributeMap.put(clazz, txAttr);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册