Spring cache 自定义Key生成策略
2016-09-01 10:51
295 查看
摘要: Spring cache
最近使用Spring cache,发现使用默认生成的key策略只使用了方法入参作为key,很不灵活,用到真实的项目中也不太靠谱,于是自己实现它的key生成策略。
参考官方文档:http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html
spring 默认的key生成实现是
感兴趣的同学自己看下,具体我就不描述了。
自定义生成策略需要实现: 接口对应方法参数,需要调用的目标对象实例,目标方法,目标方法入参
下面展示我实现的方式,仅供参考
这里必须要知道的是,spring cache在判断是否命中数据时,是拿着生成的(key对象)调用它的是equals进行匹配,如equals相同则为命中,返回缓存数据,其次key对象必须是实现Serializable接口的。
下面展示我的具体Key实现:结合我的业务(说白了就是拿着现有的参数,目标对象,目标方法,目标入参,生成一个key对象,如果下一个对象参数一致,让他们的equals相同,就可以命中数据了..)
其实代码比较简单,重要点在于:ReflectUtil.beanToMap(ele);那一行,把javaBean转换成Map。
查看具体的Map底层对equals的实现,它是对它包含的所以数据进行equals比较的:
参考java.util.AbstractMap<K, V>
最后在配置文件中注册使用自定义的key生成策略
ClassScaner的代码 http://git.oschina.net/lis1314/codes/vxbyrealzs1uhi842g5no89#
ReflectUtil的代码 http://git.oschina.net/lis1314/codes/zilgs1caq7u89k3omjpw522
最近使用Spring cache,发现使用默认生成的key策略只使用了方法入参作为key,很不灵活,用到真实的项目中也不太靠谱,于是自己实现它的key生成策略。
参考官方文档:http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html
spring 默认的key生成实现是
org.springframework.cache.interceptor.SimpleKeyGenerator
感兴趣的同学自己看下,具体我就不描述了。
自定义生成策略需要实现: 接口对应方法参数,需要调用的目标对象实例,目标方法,目标方法入参
public interface KeyGenerator { /** * Generate a key for the given method and its parameters. * @param target the target instance * @param method the method being called * @param params the method parameters (with any var-args expanded) * @return a generated key */ Object generate(Object target, Method method, Object... params); }
下面展示我实现的方式,仅供参考
/** * 实现spring cache的默认缓存实现策略 * @author lisuo * */ public class DefaultKeyGenerator implements KeyGenerator { @Override public Object generate(Object target, Method method, Object... params) { return new DefaultKey(target, method, params); } }
这里必须要知道的是,spring cache在判断是否命中数据时,是拿着生成的(key对象)调用它的是equals进行匹配,如equals相同则为命中,返回缓存数据,其次key对象必须是实现Serializable接口的。
下面展示我的具体Key实现:结合我的业务(说白了就是拿着现有的参数,目标对象,目标方法,目标入参,生成一个key对象,如果下一个对象参数一致,让他们的equals相同,就可以命中数据了..)
/** * Spring cache key 生成策略 * 类名+方法名+参数信息 * 如果key的hashCode与equals一致,认为是同一个Key * 如果传入对象是BaseModel,那么便利它所有的一级属性,如果所有一级属性的hashCode一致, * 则认为Key相同 * @author lisuo */ public class DefaultKey implements Serializable{ private static final long serialVersionUID = 1930236297081366076L; //使用Transient,不序列化这个字段 @Transient private static final Set<Class<?>> BIZ_CLASS_TYPE; //初始化 static{ //使用类扫描工具类, 扫描项目包中BaseModel.class的所有子类,把他们放到一个Set中 //换种思想,假设项目包比较规范,没有父类的情况可以扫描包 //比如ClassScaner.scan(new String []{"com.xxx.**.model","com.xxx.**.vo"}); BIZ_CLASS_TYPE = ClassScaner.scan("com.mypackage", BaseModel.class); } /** 调用目标对象全类名 */ private String targetClassName; /** 调用目标方法名称 */ private String methodName; /** 调用目标参数 */ private Object[] params; private final int hashCode; public DefaultKey(Object target, Method method, Object[] elements) { this.targetClassName = target.getClass().getName(); this.methodName = generatorMethodName(method); if(ArrayUtils.isNotEmpty(elements)){ this.params = new Object[elements.length]; for(int i =0;i<elements.length;i++){ Object ele = elements[i]; if(ele !=null && BIZ_CLASS_TYPE.contains(ele.getClass())){ this.params[i] = ReflectUtil.beanToMap(ele); }else{ this.params[i] = ele; } } } this.hashCode = generatorHashCode(); } @Transient private String generatorMethodName(Method method){ StringBuilder builder = new StringBuilder(method.getName()); Class<?>[] types = method.getParameterTypes(); if(ArrayUtils.isNotEmpty(types)){ builder.append("("); for(Class<?> type:types){ String name = type.getName(); builder.append(name+","); } builder.append(")"); } return builder.toString(); } //生成hashCode @Transient private int generatorHashCode() { final int prime = 31; int result = 1; result = prime * result + hashCode; result = prime * result + ((methodName == null) ? 0 : methodName.hashCode()); result = prime * result + Arrays.hashCode(params); result = prime * result + ((targetClassName == null) ? 0 : targetClassName.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; DefaultKey other = (DefaultKey) obj; if (hashCode != other.hashCode) return false; if (methodName == null) { if (other.methodName != null) return false; } else if (!methodName.equals(other.methodName)) return false; if (!Arrays.equals(params, other.params)) return false; if (targetClassName == null) { if (other.targetClassName != null) return false; } else if (!targetClassName.equals(other.targetClassName)) return false; return true; } @Override public final int hashCode() { return hashCode; } }
其实代码比较简单,重要点在于:ReflectUtil.beanToMap(ele);那一行,把javaBean转换成Map。
查看具体的Map底层对equals的实现,它是对它包含的所以数据进行equals比较的:
参考java.util.AbstractMap<K, V>
public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Map)) return false; Map<?, ?> m = (Map<?, ?>) o; if (m.size() != size()) return false; try { Iterator<Entry<K, V>> i = entrySet().iterator(); while (i.hasNext()) { Entry<K, V> e = i.next(); K key = e.getKey(); V value = e.getValue(); if (value == null) { if (!(m.get(key) == null && m.containsKey(key))) return false; } else { if (!value.equals(m.get(key))) return false; } } } catch (ClassCastException unused) { return false; } catch (NullPointerException unused) { return false; } return true; }
最后在配置文件中注册使用自定义的key生成策略
<!-- Key生成策略配置 --> <bean id="defaultKeyGenerator" class="xxx.cache.DefaultKeyGenerator"/> <!-- 开启spring缓存注解 --> <cache:annotation-driven cache-manager="cacheManager" key-generator="defaultKeyGenerator"/>
ClassScaner的代码 http://git.oschina.net/lis1314/codes/vxbyrealzs1uhi842g5no89#
ReflectUtil的代码 http://git.oschina.net/lis1314/codes/zilgs1caq7u89k3omjpw522
相关文章推荐
- 自定义主键生成策略
- 自定义主键的生成策略
- hibernate自定义主键生成策略
- hibernate自定义主键生成策略
- 并发自定义主键生成策略
- 160727、自定义hibernate主键生成策略生成字符串+数字自增长
- mybatis的自定义主键生成策略
- Hibernate自定义主键生成策略
- 缓存key生成策略的一些思考
- jooq使用自定义策略生成代码(How to use a custom strategy with the jOOQ code-generator and Maven?)
- hibernate自定义主键生成策略2---关于Configurable接口继承和PersistentIdentifierGenerator常量的测试
- Hibernate初学者---自定义生成ID策略的步骤
- 自定义主键的生成策略
- hibernate自定义主键生成策略
- java,url长链接生成短链接,短链接生成器,自定义字符串,对字符串md5混合KEY加密,根据短链接获得key值,不重复的随机数,不重复的随机字符串
- 很好用的生成BarCode的自定义Tag
- 自定义表单数据信息生成
- 通过自定义的域策略管理模板修改vmwaredhcp服务启动
- 网站生成静态页面攻略3:防采集策略
- 网站生成静态页面,及网站数据采集的攻、防原理和策略