|
|
|
@ -1,5 +1,5 @@ |
|
|
|
/* |
|
|
|
/* |
|
|
|
* Copyright 2002-2021 the original author or authors. |
|
|
|
* Copyright 2002-2024 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. |
|
|
|
@ -32,20 +32,16 @@ import org.springframework.lang.Nullable; |
|
|
|
import org.springframework.util.ClassUtils; |
|
|
|
import org.springframework.util.ClassUtils; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Abstract implementation of {@link CacheOperation} that caches attributes |
|
|
|
* Abstract implementation of {@link CacheOperationSource} that caches operations |
|
|
|
* for methods and implements a fallback policy: 1. specific target method; |
|
|
|
* for methods and implements a fallback policy: 1. specific target method; |
|
|
|
* 2. target class; 3. declaring method; 4. declaring class/interface. |
|
|
|
* 2. target class; 3. declaring method; 4. declaring class/interface. |
|
|
|
* |
|
|
|
* |
|
|
|
* <p>Defaults to using the target class's caching attribute if none is |
|
|
|
* <p>Defaults to using the target class's declared cache operations if none are |
|
|
|
* associated with the target method. Any caching attribute associated with |
|
|
|
* associated with the target method. Any cache operations associated with |
|
|
|
* the target method completely overrides a class caching attribute. |
|
|
|
* the target method completely override any class-level declarations. |
|
|
|
* If none found on the target class, the interface that the invoked method |
|
|
|
* If none found on the target class, the interface that the invoked method |
|
|
|
* has been called through (in case of a JDK proxy) will be checked. |
|
|
|
* has been called through (in case of a JDK proxy) will be checked. |
|
|
|
* |
|
|
|
* |
|
|
|
* <p>This implementation caches attributes by method after they are first |
|
|
|
|
|
|
|
* used. If it is ever desirable to allow dynamic changing of cacheable |
|
|
|
|
|
|
|
* attributes (which is very unlikely), caching could be made configurable. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @author Costin Leau |
|
|
|
* @author Costin Leau |
|
|
|
* @author Juergen Hoeller |
|
|
|
* @author Juergen Hoeller |
|
|
|
* @since 3.1 |
|
|
|
* @since 3.1 |
|
|
|
@ -53,10 +49,10 @@ import org.springframework.util.ClassUtils; |
|
|
|
public abstract class AbstractFallbackCacheOperationSource implements CacheOperationSource { |
|
|
|
public abstract class AbstractFallbackCacheOperationSource implements CacheOperationSource { |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Canonical value held in cache to indicate no caching attribute was |
|
|
|
* Canonical value held in cache to indicate no cache operation was |
|
|
|
* found for this method and we don't need to look again. |
|
|
|
* found for this method, and we don't need to look again. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private static final Collection<CacheOperation> NULL_CACHING_ATTRIBUTE = Collections.emptyList(); |
|
|
|
private static final Collection<CacheOperation> NULL_CACHING_MARKER = Collections.emptyList(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -71,14 +67,14 @@ public abstract class AbstractFallbackCacheOperationSource implements CacheOpera |
|
|
|
* <p>As this base class is not marked Serializable, the cache will be recreated |
|
|
|
* <p>As this base class is not marked Serializable, the cache will be recreated |
|
|
|
* after serialization - provided that the concrete subclass is Serializable. |
|
|
|
* after serialization - provided that the concrete subclass is Serializable. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private final Map<Object, Collection<CacheOperation>> attributeCache = new ConcurrentHashMap<>(1024); |
|
|
|
private final Map<Object, Collection<CacheOperation>> operationCache = new ConcurrentHashMap<>(1024); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Determine the caching attribute for this method invocation. |
|
|
|
* Determine the cache operations for this method invocation. |
|
|
|
* <p>Defaults to the class's caching attribute if no method attribute is found. |
|
|
|
* <p>Defaults to class-declared metadata if no method-level metadata is found. |
|
|
|
* @param method the method for the current invocation (never {@code null}) |
|
|
|
* @param method the method for the current invocation (never {@code null}) |
|
|
|
* @param targetClass the target class for this invocation (may be {@code null}) |
|
|
|
* @param targetClass the target class for this invocation (can be {@code null}) |
|
|
|
* @return {@link CacheOperation} for this method, or {@code null} if the method |
|
|
|
* @return {@link CacheOperation} for this method, or {@code null} if the method |
|
|
|
* is not cacheable |
|
|
|
* is not cacheable |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@ -90,21 +86,21 @@ public abstract class AbstractFallbackCacheOperationSource implements CacheOpera |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Object cacheKey = getCacheKey(method, targetClass); |
|
|
|
Object cacheKey = getCacheKey(method, targetClass); |
|
|
|
Collection<CacheOperation> cached = this.attributeCache.get(cacheKey); |
|
|
|
Collection<CacheOperation> cached = this.operationCache.get(cacheKey); |
|
|
|
|
|
|
|
|
|
|
|
if (cached != null) { |
|
|
|
if (cached != null) { |
|
|
|
return (cached != NULL_CACHING_ATTRIBUTE ? cached : null); |
|
|
|
return (cached != NULL_CACHING_MARKER ? cached : null); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
Collection<CacheOperation> cacheOps = computeCacheOperations(method, targetClass); |
|
|
|
Collection<CacheOperation> cacheOps = computeCacheOperations(method, targetClass); |
|
|
|
if (cacheOps != null) { |
|
|
|
if (cacheOps != null) { |
|
|
|
if (logger.isTraceEnabled()) { |
|
|
|
if (logger.isTraceEnabled()) { |
|
|
|
logger.trace("Adding cacheable method '" + method.getName() + "' with attribute: " + cacheOps); |
|
|
|
logger.trace("Adding cacheable method '" + method.getName() + "' with operations: " + cacheOps); |
|
|
|
} |
|
|
|
} |
|
|
|
this.attributeCache.put(cacheKey, cacheOps); |
|
|
|
this.operationCache.put(cacheKey, cacheOps); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
this.attributeCache.put(cacheKey, NULL_CACHING_ATTRIBUTE); |
|
|
|
this.operationCache.put(cacheKey, NULL_CACHING_MARKER); |
|
|
|
} |
|
|
|
} |
|
|
|
return cacheOps; |
|
|
|
return cacheOps; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -129,7 +125,7 @@ public abstract class AbstractFallbackCacheOperationSource implements CacheOpera |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// The method may be on an interface, but we need attributes from the target class.
|
|
|
|
// The method may be on an interface, but we need metadata from the target class.
|
|
|
|
// If the target class is null, the method will be unchanged.
|
|
|
|
// If the target class is null, the method will be unchanged.
|
|
|
|
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass); |
|
|
|
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass); |
|
|
|
|
|
|
|
|
|
|
|
@ -163,19 +159,19 @@ public abstract class AbstractFallbackCacheOperationSource implements CacheOpera |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Subclasses need to implement this to return the caching attribute for the |
|
|
|
* Subclasses need to implement this to return the cache operations for the |
|
|
|
* given class, if any. |
|
|
|
* given class, if any. |
|
|
|
* @param clazz the class to retrieve the attribute for |
|
|
|
* @param clazz the class to retrieve the cache operations for |
|
|
|
* @return all caching attribute associated with this class, or {@code null} if none |
|
|
|
* @return all cache operations associated with this class, or {@code null} if none |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@Nullable |
|
|
|
@Nullable |
|
|
|
protected abstract Collection<CacheOperation> findCacheOperations(Class<?> clazz); |
|
|
|
protected abstract Collection<CacheOperation> findCacheOperations(Class<?> clazz); |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Subclasses need to implement this to return the caching attribute for the |
|
|
|
* Subclasses need to implement this to return the cache operations for the |
|
|
|
* given method, if any. |
|
|
|
* given method, if any. |
|
|
|
* @param method the method to retrieve the attribute for |
|
|
|
* @param method the method to retrieve the cache operations for |
|
|
|
* @return all caching attribute associated with this method, or {@code null} if none |
|
|
|
* @return all cache operations associated with this method, or {@code null} if none |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@Nullable |
|
|
|
@Nullable |
|
|
|
protected abstract Collection<CacheOperation> findCacheOperations(Method method); |
|
|
|
protected abstract Collection<CacheOperation> findCacheOperations(Method method); |
|
|
|
|