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

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生成策略还能用吗?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值