Browse Source

DefaultTransactionAttribute stores descriptor (method identification)

Issue: SPR-14760
pull/1215/head
Juergen Hoeller 8 years ago
parent
commit
52b029d71d
  1. 21
      spring-core/src/main/java/org/springframework/util/ClassUtils.java
  2. 40
      spring-tx/src/main/java/org/springframework/transaction/interceptor/AbstractFallbackTransactionAttributeSource.java
  3. 29
      spring-tx/src/main/java/org/springframework/transaction/interceptor/DefaultTransactionAttribute.java
  4. 21
      spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java
  5. 8
      spring-tx/src/test/java/org/springframework/transaction/interceptor/MapTransactionAttributeSource.java

21
spring-core/src/main/java/org/springframework/util/ClassUtils.java

@ -511,8 +511,21 @@ public abstract class ClassUtils { @@ -511,8 +511,21 @@ public abstract class ClassUtils {
* @return the qualified name of the 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");
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();
}
else if (candidates.isEmpty()) {
throw new IllegalStateException("Expected method not found: " + clazz + "." + methodName);
throw new IllegalStateException("Expected method not found: " + clazz.getName() + '.' + methodName);
}
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) {
Assert.notNull(resourceName, "Resource name must not be null");
if (!resourceName.startsWith("/")) {
return classPackageAsResourcePath(clazz) + "/" + resourceName;
return classPackageAsResourcePath(clazz) + '/' + resourceName;
}
return classPackageAsResourcePath(clazz) + resourceName;
}

40
spring-tx/src/main/java/org/springframework/transaction/interceptor/AbstractFallbackTransactionAttributeSource.java

@ -97,20 +97,22 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran @@ -97,20 +97,22 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran
}
else {
// We need to work it out.
TransactionAttribute txAtt = computeTransactionAttribute(method, targetClass);
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// Put it in the cache.
if (txAtt == null) {
if (txAttr == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
if (txAttr instanceof DefaultTransactionAttribute) {
((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
}
if (logger.isDebugEnabled()) {
Class<?> classToLog = (targetClass != null ? targetClass : method.getDeclaringClass());
logger.debug("Adding transactional method '" + classToLog.getSimpleName() + "." +
method.getName() + "' with attribute: " + txAtt);
logger.debug("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
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);
// First try is the method in the target class.
TransactionAttribute txAtt = findTransactionAttribute(specificMethod);
if (txAtt != null) {
return txAtt;
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// Second try is the transaction attribute on the target class.
txAtt = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAtt != null && ClassUtils.isUserLevelMethod(method)) {
return txAtt;
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
if (specificMethod != method) {
// Fallback is to look at the original method.
txAtt = findTransactionAttribute(method);
if (txAtt != null) {
return txAtt;
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
// Last fallback is the class of the original method.
txAtt = findTransactionAttribute(method.getDeclaringClass());
if (txAtt != null && ClassUtils.isUserLevelMethod(method)) {
return txAtt;
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}

29
spring-tx/src/main/java/org/springframework/transaction/interceptor/DefaultTransactionAttribute.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* 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");
* 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;
/**
* Transaction attribute that takes the EJB approach to rolling
* back on runtime, but not checked, exceptions.
* Spring's common transaction attribute implementation.
* Rolls back on runtime, but not checked, exceptions by default.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 16.03.2003
*/
@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 descriptor;
/**
* 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.
* <p>This may be used for choosing a corresponding transaction manager
* to process this specific transaction.
* @since 3.0
*/
public void setQualifier(String 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.
* @since 3.0
*/
@Override
public String getQualifier() {
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.
* Additionally attempt to rollback on Error.

21
spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java

@ -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.support.CallbackPreferringPlatformTransactionManager;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.util.ClassUtils;
import org.springframework.util.ConcurrentReferenceHashMap;
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.
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// 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;
}
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
* for use in logging. Can be overridden in subclasses to provide a
* 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 targetClass the class that the method is being invoked on
* @return a String representation identifying this method
* @see org.springframework.util.ClassUtils#getQualifiedMethodName
*/
protected String methodIdentification(Method method, Class<?> targetClass) {
return (targetClass != null ? targetClass : method.getDeclaringClass()).getName() + "." + method.getName();
return null;
}
/**

8
spring-tx/src/test/java/org/springframework/transaction/interceptor/MapTransactionAttributeSource.java

@ -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<>();
public void register(Method method, TransactionAttribute txAtt) {
this.attributeMap.put(method, txAtt);
public void register(Method method, TransactionAttribute txAttr) {
this.attributeMap.put(method, txAttr);
}
public void register(Class<?> clazz, TransactionAttribute txAtt) {
this.attributeMap.put(clazz, txAtt);
public void register(Class<?> clazz, TransactionAttribute txAttr) {
this.attributeMap.put(clazz, txAttr);
}

Loading…
Cancel
Save