spring boot cache redis 简单理解自定义 KeyGenerator
简单理解自定义 KeyGenerator
一般情况我们在 spring boot 中会使用 redis 作为缓存 但我们是需要自定义 cache key 的生成方式
1.为什么不使用 spring 默认的 生成策略?
先看看源码:
public class DefaultKeyGenerator implements KeyGenerator { public static final int NO_PARAM_KEY = 0; public static final int NULL_PARAM_KEY = 53; public DefaultKeyGenerator() { } public Object generate(Object target, Method method, Object... params) { if (params.length == 0) {//没有参数直接返回 0 return 0; } else { if (params.length == 1) { Object param = params[0]; if (param == null) {//有一个参数 并且为 null 返回 53 return 53; }//参数不是数组 直接返回参数 if (!param.getClass().isArray()) { return param; } }//其它情况 返回 深度计算的 hashcode 简单理解可以认为就是一个 hashcode return Arrays.deepHashCode(params); } }}
DefaultKeyGenerator 最终返回的 缓存键值当参数列表的值相同时是一样的 这样就会造成获取到错误的缓存数据
spring 还有一个 生成策略 同样也是有这样的 问题
public class SimpleKeyGenerator implements KeyGenerator { @Override public Object generate(Object target, Method method, Object... params) { return generateKey(params); } /** * Generate a key based on the specified parameters. */ public static Object generateKey(Object... params) { if (params.length == 0) { return SimpleKey.EMPTY; } if (params.length == 1) { Object param = params[0]; if (param != null && !param.getClass().isArray()) { return param; } } return new SimpleKey(params); }}public class SimpleKey implements Serializable { public static final SimpleKey EMPTY = new SimpleKey(); private final Object[] params; private final int hashCode; /** * Create a new {@link SimpleKey} instance. * @param elements the elements of the key */ public SimpleKey(Object... elements) { Assert.notNull(elements, "Elements must not be null"); this.params = new Object[elements.length]; System.arraycopy(elements, 0, this.params, 0, elements.length); this.hashCode = Arrays.deepHashCode(this.params); } @Override public boolean equals(Object obj) { return (this == obj || (obj instanceof SimpleKey && Arrays.deepEquals(this.params, ((SimpleKey) obj).params))); } @Override public final int hashCode() { return this.hashCode; } @Override public String toString() { return getClass().getSimpleName() + " [" + StringUtils.arrayToCommaDelimitedString(this.params) + "]"; }}
最后 cache key 使用的是这个
return getClass().getSimpleName() + " [" + StringUtils.arrayToCommaDelimitedString(this.params) + "]";
这也会在一定的情况下出现获取到错误的缓存数据
所以我们需要自己自定义 cache key 的生成方式
我一般是这样用的 类名+方法名+参数列表的类型+参数值 再做 哈希散列 作为key
@Beanpublic KeyGenerator myKeyGenerator(){ return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append(method.getName()); sb.append("&"); for (Object obj : params) { if (obj != null){ sb.append(obj.getClass().getName()); sb.append("&"); sb.append(JSON.toJSONString(obj)); sb.append("&"); } } log.info("redis cache key str: "+sb.toString()); log.info("redis cache key sha256Hex: "+DigestUtils.sha256Hex(sb.toString())); return DigestUtils.sha256Hex(sb.toString()); } };}
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。