pom.xml
<!-- ehcache -->
<dependency>
<groupId>com.googlecode.ehcache-spring-annotations</groupId>
<artifactId>ehcache-spring-annotations</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>${ehcache.version}</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>${ehcache.version}</version>
</dependency>
说明:
本文说的不是Spring Cache, ehcache-spring-annotations需要配合ehcache使用. 在代码中只是加注解(@Cacheable)而已
@Cacheable(cacheName="myCache")
public ForumPermissions getPermissions(GlobalPermissionEnum permissonType){
}
@Cacheable的全名: com.googlecode.ehcache.annotations.Cacheable,不要跟Spring Cache的同名注解(org.springframework.cache.annotation.Cacheable)混为一体
@Cacheable
@Target(value = {ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {
public String cacheName();
public boolean cacheNull() default true;
public DecoratedCacheType decoratedCacheType() default DecoratedCacheType.NONE;
@Deprecated
public boolean selfPopulating() default false;
public int selfPopulatingTimeout() default 0;
public long refreshInterval() default 60000L;
public String keyGeneratorName() default "";
public String exceptionCacheName() default "";
public KeyGenerator keyGenerator() default @KeyGenerator(name = "");
public String cacheableInteceptorName() default "";
public String resolverFactoryName() default "";
public ResolverFactory resolverFactory() default @ResolverFactory(name = "");
}
说明:
keyGeneratorName和keyGenerator在下一篇中详细说说.refreshInterval默认是一分钟(60000L).一般只需要为cacheName设置一个值
缓存的Key
内存缓存大多都是key-value键值存储,注解中的keyGeneratorName和keyGenerator是可以指定一个自定义key生成策略.不指定默认使用的是:com.googlecode.ehcache.annotations.key.HashCodeCacheKeyGenerator
package com.googlecode.ehcache.annotations.key;
/**
* @author Eric Dalquist
* @version $Revision: 656 $
*/
public class HashCodeCacheKeyGenerator extends AbstractHashingCacheKeyGenerator<HashCodeCacheKeyGenerator.LongGenerator, Long> {}
这里都不一一列出类的层次结构了.有兴趣的可以翻墙去下源码.下面是具体作生成的方法
package com.googlecode.ehcache.annotations.key;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.IdentityHashMap;
import java.util.Map;
import org.aopalliance.intercept.MethodInvocation;
/**
* Base class for cache key generators. Handles common logic for including/excluding the method
* signature from key generation. Also provides support for avoiding circular references for key
* generators that traverse the argument object graph via the {@link #register(Object)} and
* {@link #unregister(Object)} APIs
*
* @author Eric Dalquist
* @version $Revision: 656 $
*/
public abstract class AbstractCacheKeyGenerator<T extends Serializable> implements CacheKeyGenerator<T> {
//ETC
/* (non-Javadoc)
* @see com.googlecode.ehcache.annotations.key.CacheKeyGenerator#generateKey(org.aopalliance.intercept.MethodInvocation)
*/
public T generateKey(MethodInvocation methodInvocation) {
final Object[] arguments = methodInvocation.getArguments();
if (this.includeMethod) {
final Method method = methodInvocation.getMethod();
final Class<?> declaringClass = method.getDeclaringClass();
final String name = method.getName();
final Class<?> returnType = method.getReturnType();
if (this.includeParameterTypes) {
final Class<?>[] parameterTypes = method.getParameterTypes();
return this.generateKey(declaringClass, name, returnType, parameterTypes, arguments);
}
return this.generateKey(declaringClass, name, returnType, arguments);
}
try {
return this.generateKey(arguments);
}
finally {
if (this.checkforCycles) {
//Cleanup our thread local data
REGISTRY.remove();
}
}
}
}
说明:
MethodInvocation 在aopalliance-1.0.jar中的org.aopalliance.intercept包下,MethodInvocation 继承了Invocation可以拿到方法的参数值(getArguments),其它的都是反射包下的Method可以拿到的
method.getName()返回方法的名字
method.getReturnType()返回方法的返回值类型
method.getParameterTypes()返回方法的参数类型
在代码中定位一个方法的元素都有了:类全名 + 方法的签名(返回值 + 方法名 + 参数列表 )
参数的值不同也可以生成唯一的key
package com.googlecode.ehcache.annotations.interceptor;
/**
* Intercepter that handles invocations on methods annotated with {@link Cacheable} or {@link TriggersRemove}.
*
* @author Eric Dalquist
* @version $Revision: 681 $
*/
public class EhCacheInterceptor implements MethodInterceptor {
//ETC
/**
* Creates a {@link Serializable} cache key from the {@link MethodInvocation} and configuration attributes.
*
* @param methodInvocation Invocation to build the key for
* @param methodAttribute Configuration for the invoked method
* @return Generated cache key, must not return null.
*/
protected Serializable generateCacheKey(MethodInvocation methodInvocation, final MethodAttribute methodAttribute) {
final CacheKeyGenerator<? extends Serializable> cacheKeyGenerator = methodAttribute.getCacheKeyGenerator();
final ParameterMask parameterMask = methodAttribute.getCacheKeyParameterMask();
if (parameterMask.shouldMask()) {
methodInvocation = new ParameterFilteringMethodInvocation(methodInvocation, parameterMask);
}
final Serializable cacheKey = cacheKeyGenerator.generateKey(methodInvocation);
this.logger.debug("Generated key '{}' for invocation: {}", cacheKey, methodInvocation);
return cacheKey;
}
}
debug日志
Generated key '-27052115907236245' for invocation: ReflectiveMethodInvocation:
public net.htage.forum.entity.ForumPermissions net.htage.forum.impl.service.spring.EhcacheCacheBox.getPermissions(net.htage.forum.entity.define.GlobalPermissionEnum);
target is of class [net.htage.forum.impl.service.spring.EhcacheCacheBox]
Generated key '-27052113702228882' for invocation: ReflectiveMethodInvocation:
public net.htage.forum.entity.ForumPermissions net.htage.forum.impl.service.spring.EhcacheCacheBox.getPermissions(net.htage.forum.entity.define.GlobalPermissionEnum);
target is of class [net.htage.forum.impl.service.spring.EhcacheCacheBox]
ReflectiveMethodInvocation :
可见性修饰符(public) +
返回值类型(net.htage.forum.entity.ForumPermissions) +
方法全名(net.htage.forum.impl.service.spring.EhcacheCacheBox.getPermissions) +
( +
参数类型列表(net.htage.forum.entity.define.GlobalPermissionEnum) +
);
也说明如果一个方法没有参数,第一次调用生成key并缓存,以后的N次调用都是同一份缓存. 在debug日志中只能搜到一份记录
Generated key '-937817555943' for invocation: ReflectiveMethodInvocation:
public java.util.List net.htage.forum.impl.service.spring.EhcacheCacheBox.getAllLevel();
target is of class [net.htage.forum.impl.service.spring.EhcacheCacheBox]
对于全局的配置来说没问题, N次调用后都是一样的结果. 但是?具有时间性的方法(同时它没有参数)则不然。第二次调用到第100调用之间数据肯定有变化的.哪这个默认的key生成策略还能用吗?