您的位置:首页 > 编程语言 > Java开发

理一理ehcache-spring-annotations缓存的Key生成

2017-09-26 11:40 363 查看
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生成策略还能用吗?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  缓存 ehcache key