+ add XML support for cache abstraction (cache-advice) - DRAFT
This commit is contained in:
@@ -48,11 +48,6 @@ import static org.springframework.context.annotation.AnnotationConfigUtils.*;
|
||||
*/
|
||||
class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
private static final String CACHE_MANAGER_ATTRIBUTE = "cache-manager";
|
||||
|
||||
private static final String DEFAULT_CACHE_MANAGER_BEAN_NAME = "cacheManager";
|
||||
|
||||
|
||||
/**
|
||||
* Parses the '<code><cache:annotation-driven/></code>' tag. Will
|
||||
* {@link AopNamespaceUtils#registerAutoProxyCreatorIfNecessary register an AutoProxyCreator}
|
||||
@@ -71,13 +66,9 @@ class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String extractCacheManager(Element element) {
|
||||
return (element.hasAttribute(CACHE_MANAGER_ATTRIBUTE) ? element.getAttribute(CACHE_MANAGER_ATTRIBUTE)
|
||||
: DEFAULT_CACHE_MANAGER_BEAN_NAME);
|
||||
}
|
||||
|
||||
private static void registerCacheManagerProperty(Element element, BeanDefinition def) {
|
||||
def.getPropertyValues().add("cacheManager", new RuntimeBeanReference(extractCacheManager(element)));
|
||||
def.getPropertyValues().add("cacheManager",
|
||||
new RuntimeBeanReference(CacheNamespaceHandler.extractCacheManager(element)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,7 +115,7 @@ class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser
|
||||
interceptorDef.setSource(eleSource);
|
||||
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
registerCacheManagerProperty(element, interceptorDef);
|
||||
interceptorDef.getPropertyValues().add("cacheOperationSource", new RuntimeBeanReference(sourceName));
|
||||
interceptorDef.getPropertyValues().add("cacheOperationSources", new RuntimeBeanReference(sourceName));
|
||||
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
|
||||
|
||||
// Create the CacheAdvisor definition.
|
||||
|
||||
171
org.springframework.context/src/main/java/org/springframework/cache/config/CacheAdviceParser.java
vendored
Normal file
171
org.springframework.context/src/main/java/org/springframework/cache/config/CacheAdviceParser.java
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright 2011 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.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cache.config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.config.TypedStringValue;
|
||||
import org.springframework.beans.factory.parsing.ReaderContext;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.ManagedMap;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.cache.annotation.AnnotationCacheOperationSource;
|
||||
import org.springframework.cache.interceptor.CacheEvictOperation;
|
||||
import org.springframework.cache.interceptor.CacheInterceptor;
|
||||
import org.springframework.cache.interceptor.CacheOperation;
|
||||
import org.springframework.cache.interceptor.CacheUpdateOperation;
|
||||
import org.springframework.cache.interceptor.NameMatchCacheOperationSource;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser
|
||||
* BeanDefinitionParser} for the {@code <tx:advice/>} tag.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*
|
||||
*/
|
||||
class CacheAdviceParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
/**
|
||||
* Simple, reusable class used for overriding defaults.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
private static class Props {
|
||||
|
||||
private String key, condition;
|
||||
private String[] caches = null;
|
||||
|
||||
Props(Element root) {
|
||||
String defaultCache = root.getAttribute("cache");
|
||||
key = root.getAttribute("key");
|
||||
condition = root.getAttribute("condition");
|
||||
|
||||
if (StringUtils.hasText(defaultCache)) {
|
||||
caches = StringUtils.commaDelimitedListToStringArray(defaultCache.trim());
|
||||
}
|
||||
}
|
||||
|
||||
CacheOperation merge(Element element, ReaderContext readerCtx, CacheOperation op) {
|
||||
String cache = element.getAttribute("cache");
|
||||
String k = element.getAttribute("key");
|
||||
String c = element.getAttribute("condition");
|
||||
|
||||
String[] localCaches = caches;
|
||||
String localKey = key, localCondition = condition;
|
||||
|
||||
// sanity check
|
||||
if (StringUtils.hasText(cache)) {
|
||||
localCaches = StringUtils.commaDelimitedListToStringArray(cache.trim());
|
||||
} else {
|
||||
if (caches == null) {
|
||||
readerCtx.error("No cache specified specified for " + element.getNodeName(), element);
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(k)) {
|
||||
localKey = k.trim();
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(c)) {
|
||||
localCondition = c.trim();
|
||||
}
|
||||
op.setCacheNames(localCaches);
|
||||
op.setKey(localKey);
|
||||
op.setCondition(localCondition);
|
||||
|
||||
return op;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String CACHEABLE_ELEMENT = "cacheable";
|
||||
private static final String CACHE_EVICT_ELEMENT = "cache-evict";
|
||||
private static final String METHOD_ATTRIBUTE = "method";
|
||||
private static final String DEFS_ELEMENT = "definitions";
|
||||
|
||||
@Override
|
||||
protected Class<?> getBeanClass(Element element) {
|
||||
return CacheInterceptor.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
builder.addPropertyReference("cacheManager", CacheNamespaceHandler.extractCacheManager(element));
|
||||
|
||||
List<Element> cacheDefs = DomUtils.getChildElementsByTagName(element, DEFS_ELEMENT);
|
||||
if (cacheDefs.size() >= 1) {
|
||||
// Using attributes source.
|
||||
List<RootBeanDefinition> attributeSourceDefinitions = parseDefinitionsSources(cacheDefs, parserContext);
|
||||
builder.addPropertyValue("cacheOperationSources", attributeSourceDefinitions);
|
||||
} else {
|
||||
// Assume annotations source.
|
||||
builder.addPropertyValue("cacheOperationSources", new RootBeanDefinition(
|
||||
AnnotationCacheOperationSource.class));
|
||||
}
|
||||
}
|
||||
|
||||
private List<RootBeanDefinition> parseDefinitionsSources(List<Element> definitions, ParserContext parserContext) {
|
||||
ManagedList<RootBeanDefinition> defs = new ManagedList<RootBeanDefinition>(definitions.size());
|
||||
|
||||
// extract default param for the definition
|
||||
for (Element element : definitions) {
|
||||
defs.add(parseDefinitionSource(element, parserContext));
|
||||
}
|
||||
|
||||
return defs;
|
||||
}
|
||||
|
||||
private RootBeanDefinition parseDefinitionSource(Element definition, ParserContext parserContext) {
|
||||
Props prop = new Props(definition);
|
||||
// add cacheable first
|
||||
|
||||
ManagedMap<TypedStringValue, CacheOperation> cacheOpeMap = new ManagedMap<TypedStringValue, CacheOperation>();
|
||||
cacheOpeMap.setSource(parserContext.extractSource(definition));
|
||||
|
||||
List<Element> updateCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHEABLE_ELEMENT);
|
||||
|
||||
for (Element opElement : updateCacheMethods) {
|
||||
String name = opElement.getAttribute(METHOD_ATTRIBUTE);
|
||||
TypedStringValue nameHolder = new TypedStringValue(name);
|
||||
nameHolder.setSource(parserContext.extractSource(opElement));
|
||||
CacheOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CacheUpdateOperation());
|
||||
|
||||
cacheOpeMap.put(nameHolder, op);
|
||||
}
|
||||
|
||||
List<Element> evictCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHE_EVICT_ELEMENT);
|
||||
|
||||
for (Element opElement : evictCacheMethods) {
|
||||
String name = opElement.getAttribute(METHOD_ATTRIBUTE);
|
||||
TypedStringValue nameHolder = new TypedStringValue(name);
|
||||
nameHolder.setSource(parserContext.extractSource(opElement));
|
||||
CacheOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CacheEvictOperation());
|
||||
|
||||
cacheOpeMap.put(nameHolder, op);
|
||||
}
|
||||
|
||||
RootBeanDefinition attributeSourceDefinition = new RootBeanDefinition(NameMatchCacheOperationSource.class);
|
||||
attributeSourceDefinition.setSource(parserContext.extractSource(definition));
|
||||
attributeSourceDefinition.getPropertyValues().add("nameMap", cacheOpeMap);
|
||||
return attributeSourceDefinition;
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.cache.config;
|
||||
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* <code>NamespaceHandler</code> allowing for the configuration of
|
||||
@@ -30,8 +31,18 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
*/
|
||||
public class CacheNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
static final String CACHE_MANAGER_ATTRIBUTE = "cache-manager";
|
||||
static final String DEFAULT_CACHE_MANAGER_BEAN_NAME = "cacheManager";
|
||||
|
||||
static String extractCacheManager(Element element) {
|
||||
return (element.hasAttribute(CacheNamespaceHandler.CACHE_MANAGER_ATTRIBUTE) ? element
|
||||
.getAttribute(CacheNamespaceHandler.CACHE_MANAGER_ATTRIBUTE)
|
||||
: CacheNamespaceHandler.DEFAULT_CACHE_MANAGER_BEAN_NAME);
|
||||
}
|
||||
|
||||
public void init() {
|
||||
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenCacheBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("advice", new CacheAdviceParser());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -117,11 +117,6 @@ public abstract class AbstractFallbackCacheOperationSource implements CacheOpera
|
||||
return new DefaultCacheKey(method, targetClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same signature as {@link #getTransactionAttribute}, but doesn't cache the result.
|
||||
* {@link #getTransactionAttribute} is effectively a caching decorator for this method.
|
||||
* @see #getTransactionAttribute
|
||||
*/
|
||||
private CacheOperation computeCacheOperationDefinition(Method method, Class<?> targetClass) {
|
||||
// Don't allow no-public methods as required.
|
||||
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
|
||||
|
||||
@@ -44,12 +44,8 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* <p>Subclasses are responsible for calling methods in this class in the correct order.
|
||||
*
|
||||
* <p>If no caching name has been specified in the <code>CacheOperationDefinition</code>,
|
||||
* the exposed name will be the <code>fully-qualified class name + "." + method name</code>
|
||||
* (by default).
|
||||
*
|
||||
* <p>Uses the <b>Strategy</b> design pattern. A <code>CacheManager</code>
|
||||
* implementation will perform the actual transaction management, and a
|
||||
* implementation will perform the actual cache management, and a
|
||||
* <code>CacheDefinitionSource</code> is used for determining caching operation definitions.
|
||||
*
|
||||
* <p>A cache aspect is serializable if its <code>CacheManager</code>
|
||||
@@ -155,6 +151,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
|
||||
return ClassUtils.getQualifiedMethodName(specificMethod);
|
||||
}
|
||||
|
||||
|
||||
protected Collection<Cache> getCaches(CacheOperation operation) {
|
||||
Set<String> cacheNames = operation.getCacheNames();
|
||||
Collection<Cache> caches = new ArrayList<Cache>(cacheNames.size());
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2011 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.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cache.interceptor;
|
||||
|
||||
import java.beans.PropertyEditorSupport;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* PropertyEditor for {@link CacheOperation} objects. Accepts a String of form
|
||||
* <p><tt>action,cache,key,condition</tt>
|
||||
* <p>where only action and cache are required. Available definitions for action are
|
||||
* <tt>cacheable</tt> and <tt>evict</tt>.
|
||||
* When specifying multiple caches, use ; as a separator
|
||||
*
|
||||
* A typical example would be:
|
||||
* <p><code>cacheable, orders;books, #p0</code>
|
||||
*
|
||||
* <p>The tokens need to be specified in the order above.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*
|
||||
* @see org.springframework.transaction.TransactionAttributeEditor
|
||||
* @see org.springframework.core.Constants
|
||||
*/
|
||||
public class CacheOperationEditor extends PropertyEditorSupport {
|
||||
|
||||
/**
|
||||
* Format is action, cache, key, condition.
|
||||
* Null or the empty string means that the method is non cacheable.
|
||||
* @see java.beans.PropertyEditor#setAsText(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void setAsText(String text) throws IllegalArgumentException {
|
||||
if (StringUtils.hasLength(text)) {
|
||||
// tokenize it with ","
|
||||
String[] tokens = StringUtils.commaDelimitedListToStringArray(text);
|
||||
if (tokens.length < 2) {
|
||||
throw new IllegalArgumentException(
|
||||
"too little arguments found, at least the cache action and cache name are required");
|
||||
}
|
||||
|
||||
CacheOperation op;
|
||||
|
||||
if ("cacheable".contains(tokens[0])) {
|
||||
op = new CacheUpdateOperation();
|
||||
}
|
||||
|
||||
else if ("evict".contains(tokens[0])) {
|
||||
op = new CacheEvictOperation();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid cache action specified " + tokens[0]);
|
||||
}
|
||||
|
||||
op.setCacheNames(StringUtils.delimitedListToStringArray(tokens[1], ";"));
|
||||
|
||||
if (tokens.length > 2) {
|
||||
op.setKey(tokens[2]);
|
||||
}
|
||||
|
||||
if (tokens.length > 3) {
|
||||
op.setCondition(tokens[3]);
|
||||
}
|
||||
|
||||
setValue(op);
|
||||
} else {
|
||||
setValue(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2010-2011 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.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cache.interceptor;
|
||||
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.framework.AbstractSingletonProxyFactoryBean;
|
||||
|
||||
/**
|
||||
* Proxy factory bean for simplified declarative caching handling.
|
||||
* This is a convenient alternative to a standard AOP
|
||||
* {@link org.springframework.aop.framework.ProxyFactoryBean}
|
||||
* with a separate {@link CachingInterceptor} definition.
|
||||
*
|
||||
* <p>This class is intended to cover the <i>typical</i> case of declarative
|
||||
* cache demarcation: namely, wrapping a singleton target object with a
|
||||
* caching proxy, proxying all the interfaces that the target implements.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @see org.springframework.aop.framework.ProxyFactoryBean
|
||||
* @see CachingInterceptor
|
||||
*/
|
||||
public class CacheProxyFactoryBean extends AbstractSingletonProxyFactoryBean {
|
||||
|
||||
private final CacheInterceptor cachingInterceptor = new CacheInterceptor();
|
||||
private Pointcut pointcut;
|
||||
|
||||
@Override
|
||||
protected Object createMainInterceptor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the caching attribute source which is used to find the cache operation
|
||||
* definition.
|
||||
*
|
||||
* @param cacheDefinitionSources cache definition sources
|
||||
*/
|
||||
public void setCacheDefinitionSources(CacheOperationSource... cacheDefinitionSources) {
|
||||
this.cachingInterceptor.setCacheOperationSources(cacheDefinitionSources);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright 2011 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.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cache.interceptor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
|
||||
/**
|
||||
* Simple {@link CacheOperationSource} implementation that
|
||||
* allows attributes to be matched by registered name.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
public class NameMatchCacheOperationSource implements CacheOperationSource, Serializable {
|
||||
|
||||
/**
|
||||
* Logger available to subclasses.
|
||||
* <p>Static for optimal serialization.
|
||||
*/
|
||||
protected static final Log logger = LogFactory.getLog(NameMatchCacheOperationSource.class);
|
||||
|
||||
/** Keys are method names; values are TransactionAttributes */
|
||||
private Map<String, CacheOperation> nameMap = new LinkedHashMap<String, CacheOperation>();
|
||||
|
||||
/**
|
||||
* Set a name/attribute map, consisting of method names
|
||||
* (e.g. "myMethod") and CacheOperation instances
|
||||
* (or Strings to be converted to CacheOperation instances).
|
||||
* @see CacheOperation
|
||||
* @see CacheOperationEditor
|
||||
*/
|
||||
public void setNameMap(Map<String, CacheOperation> nameMap) {
|
||||
for (Map.Entry<String, CacheOperation> entry : nameMap.entrySet()) {
|
||||
addCacheMethod(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given properties into a name/attribute map.
|
||||
* Expects method names as keys and String attributes definitions as values,
|
||||
* parsable into CacheOperation instances via CacheOperationEditor.
|
||||
* @see #setNameMap
|
||||
* @see CacheOperationEditor
|
||||
*/
|
||||
public void setProperties(Properties cacheOperations) {
|
||||
CacheOperationEditor tae = new CacheOperationEditor();
|
||||
Enumeration propNames = cacheOperations.propertyNames();
|
||||
while (propNames.hasMoreElements()) {
|
||||
String methodName = (String) propNames.nextElement();
|
||||
String value = cacheOperations.getProperty(methodName);
|
||||
tae.setAsText(value);
|
||||
CacheOperation op = (CacheOperation) tae.getValue();
|
||||
addCacheMethod(methodName, op);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an attribute for a cacheable method.
|
||||
* <p>Method names can be exact matches, or of the pattern "xxx*",
|
||||
* "*xxx" or "*xxx*" for matching multiple methods.
|
||||
* @param methodName the name of the method
|
||||
* @param operation operation associated with the method
|
||||
*/
|
||||
public void addCacheMethod(String methodName, CacheOperation operation) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Adding method [" + methodName + "] with cache operation [" + operation + "]");
|
||||
}
|
||||
this.nameMap.put(methodName, operation);
|
||||
}
|
||||
|
||||
public CacheOperation getCacheOperation(Method method, Class<?> targetClass) {
|
||||
// look for direct name match
|
||||
String methodName = method.getName();
|
||||
CacheOperation attr = this.nameMap.get(methodName);
|
||||
|
||||
if (attr == null) {
|
||||
// Look for most specific name match.
|
||||
String bestNameMatch = null;
|
||||
for (String mappedName : this.nameMap.keySet()) {
|
||||
if (isMatch(methodName, mappedName)
|
||||
&& (bestNameMatch == null || bestNameMatch.length() <= mappedName.length())) {
|
||||
attr = this.nameMap.get(mappedName);
|
||||
bestNameMatch = mappedName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the given method name matches the mapped name.
|
||||
* <p>The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches,
|
||||
* as well as direct equality. Can be overridden in subclasses.
|
||||
* @param methodName the method name of the class
|
||||
* @param mappedName the name in the descriptor
|
||||
* @return if the names match
|
||||
* @see org.springframework.util.PatternMatchUtils#simpleMatch(String, String)
|
||||
*/
|
||||
protected boolean isMatch(String methodName, String mappedName) {
|
||||
return PatternMatchUtils.simpleMatch(mappedName, methodName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof NameMatchCacheOperationSource)) {
|
||||
return false;
|
||||
}
|
||||
NameMatchCacheOperationSource otherTas = (NameMatchCacheOperationSource) other;
|
||||
return ObjectUtils.nullSafeEquals(this.nameMap, otherTas.nameMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return NameMatchCacheOperationSource.class.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + ": " + this.nameMap;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user