15 changed files with 676 additions and 26 deletions
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,30 @@ |
|||||||
|
/* |
||||||
|
* 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.config; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* @author Costin Leau |
||||||
|
*/ |
||||||
|
public class CacheAdviceNamespaceTests extends AbstractAnnotationTests { |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
protected String getConfig() { |
||||||
|
return "/org/springframework/cache/config/cache-advice.xml"; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,59 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||||
|
xmlns:aop="http://www.springframework.org/schema/aop" |
||||||
|
xmlns:cache="http://www.springframework.org/schema/cache" |
||||||
|
xmlns:p="http://www.springframework.org/schema/p" |
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd |
||||||
|
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd |
||||||
|
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> |
||||||
|
|
||||||
|
<cache:advice id="cacheAdviceInterface" cache-manager="cacheManager"> |
||||||
|
<cache:definitions cache="default"> |
||||||
|
<cache:cacheable method="cache"/> |
||||||
|
<cache:cacheable method="conditional" condition="#classField == 3"/> |
||||||
|
<cache:cacheable method="key" key="#p0"/> |
||||||
|
<cache:cacheable method="nam*" key="#root.methodName"/> |
||||||
|
<cache:cacheable method="rootVars" key="#root.methodName + #root.method.name + #root.targetClass + #root.target"/> |
||||||
|
<cache:cacheable method="nullValue" cache="default"/> |
||||||
|
</cache:definitions> |
||||||
|
<cache:definitions> |
||||||
|
<cache:cache-evict method="invalidate" cache="default"/> |
||||||
|
<cache:cache-evict method="evict" key="#p0" cache="default"/> |
||||||
|
</cache:definitions> |
||||||
|
</cache:advice> |
||||||
|
|
||||||
|
<cache:advice id="cacheAdviceClass" cache-manager="cacheManager"> |
||||||
|
<cache:definitions cache="default"> |
||||||
|
<cache:cacheable method="key" key="#p0"/> |
||||||
|
<cache:cacheable method="nam*" key="#root.methodName + #root.caches[0].name"/> |
||||||
|
<cache:cacheable method="rootVars" key="#root.methodName + #root.method.name + #root.targetClass + #root.target"/> |
||||||
|
<cache:cacheable method="cache"/> |
||||||
|
<cache:cacheable method="conditional"/> |
||||||
|
<cache:cacheable method="null*"/> |
||||||
|
</cache:definitions> |
||||||
|
<cache:definitions> |
||||||
|
<cache:cache-evict method="invalidate" cache="default"/> |
||||||
|
<cache:cache-evict method="evict" key="#p0" cache="default"/> |
||||||
|
</cache:definitions> |
||||||
|
</cache:advice> |
||||||
|
|
||||||
|
<aop:config> |
||||||
|
<aop:advisor advice-ref="cacheAdviceInterface" pointcut="execution(* *..DefaultCacheableService.*(..))" order="1"/> |
||||||
|
<aop:advisor advice-ref="cacheAdviceClass" pointcut="execution(* *..AnnotatedClassCacheableService.*(..))" order="1"/> |
||||||
|
<aop:advisor advice-ref="debugInterceptor" pointcut="execution(* *..CacheableService.*(..))" order="2"/> |
||||||
|
</aop:config> |
||||||
|
|
||||||
|
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager"> |
||||||
|
<property name="caches"> |
||||||
|
<set> |
||||||
|
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default"/> |
||||||
|
</set> |
||||||
|
</property> |
||||||
|
</bean> |
||||||
|
|
||||||
|
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor"/> |
||||||
|
|
||||||
|
<bean id="service" class="org.springframework.cache.config.DefaultCacheableService"/> |
||||||
|
|
||||||
|
<bean id="classService" class="org.springframework.cache.config.AnnotatedClassCacheableService"/> |
||||||
|
</beans> |
||||||
Loading…
Reference in new issue