Consistent cache key implementation across transaction and cache attribute sources

Includes consistent applicability of class-level metadata to user-level methods only.

Issue: SPR-14017
Issue: SPR-14095
This commit is contained in:
Juergen Hoeller
2016-03-30 14:13:04 +02:00
parent 5619b005f0
commit 14bf6509ec
5 changed files with 135 additions and 86 deletions

View File

@@ -25,8 +25,8 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.MethodClassKey;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
/**
* Abstract implementation of {@link TransactionAttributeSource} that caches
@@ -65,7 +65,7 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran
protected final Log logger = LogFactory.getLog(getClass());
/**
* Cache of TransactionAttributes, keyed by DefaultCacheKey (Method + target Class).
* Cache of TransactionAttributes, keyed by method on a specific target class.
* <p>As this base class is not marked Serializable, the cache will be recreated
* after serialization - provided that the concrete subclass is Serializable.
*/
@@ -123,7 +123,7 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran
* @return the cache key (never {@code null})
*/
protected Object getCacheKey(Method method, Class<?> targetClass) {
return new DefaultCacheKey(method, targetClass);
return new MethodClassKey(method, targetClass);
}
/**
@@ -203,55 +203,4 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran
return false;
}
/**
* Default cache key for the TransactionAttribute cache.
*/
private static final class DefaultCacheKey implements Comparable<DefaultCacheKey> {
private final Method method;
private final Class<?> targetClass;
public DefaultCacheKey(Method method, Class<?> targetClass) {
this.method = method;
this.targetClass = targetClass;
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof DefaultCacheKey)) {
return false;
}
DefaultCacheKey otherKey = (DefaultCacheKey) other;
return (this.method.equals(otherKey.method) &&
ObjectUtils.nullSafeEquals(this.targetClass, otherKey.targetClass));
}
@Override
public int hashCode() {
return this.method.hashCode() + (this.targetClass != null ? this.targetClass.hashCode() * 29 : 0);
}
@Override
public String toString() {
return this.method + (this.targetClass != null ? " on " + this.targetClass : "");
}
@Override
public int compareTo(DefaultCacheKey other) {
int result = this.method.getName().compareTo(other.method.getName());
if (result == 0) {
result = this.method.toString().compareTo(other.method.toString());
if (result == 0 && this.targetClass != null) {
result = this.targetClass.getName().compareTo(other.targetClass.getName());
}
}
return result;
}
}
}