场景:
集群项目使用访问策略使用的随机,缓存使用的redis,自定义key当传入两个参数以上时候,使用Arrays.deepHashCode来计算缓存的key。但是由于被缓存的方法有个固定的User.class参数,不过在deepHashCode方法中这个class不同的机器生成不同的值,导致产生的hashcode不一样。
发现问题:
然后出现在机器1刚访问过这个接口,redis也有缓存,访问到机器2的时候仍然走service方法,也就是没有从redis取缓存。
(从日志看是否走的缓存,在自定义key生成里面打上日志,和接口调用的service打上日志,如果走了自定义key方法两遍就是在生成缓存,如果走一遍自定义key这个方法就是取的缓存)
然后找日志,同一个接口,在访问到不同机器的时候,生成的缓存key不一样,所以导致每个机器都需要缓存一遍。
原因:生成hash key的方法为Arrays.deepHashCode看方法,没有对class类型的判断
public static int deepHashCode(Object a[]) {
if (a == null)
return 0;
int result = 1;
for (Object element : a) {
int elementHash = 0;
if (element instanceof Object[])
elementHash = deepHashCode((Object[]) element);
else if (element instanceof byte[])
elementHash = hashCode((byte[]) element);
else if (element instanceof short[])
elementHash = hashCode((short[]) element);
else if (element instanceof int[])
elementHash = hashCode((int[]) element);
else if (element instanceof long[])
elementHash = hashCode((long[]) element);
else if (element instanceof char[])
elementHash = hashCode((char[]) element);
else if (element instanceof float[])
elementHash = hashCode((float[]) element);
else if (element instanceof double[])
elementHash = hashCode((double[]) element);
else if (element instanceof boolean[])
elementHash = hashCode((boolean[]) element);
else if (element != null)
elementHash = element.hashCode();
result = 31 * result + elementHash;
}
return result;
}
查看User.class参数生成缓存key的时候,每台机器生成的代理class内容不一样,然后导致使用这个class内容生成的缓存不一致。所以集群情况下就会导致同一接口,不同机器生成各自的缓存key。
重写一下deepHashCode,这是改好的结果
可以在集群情况下。每个机器上,相同参数的情况下,保持生成的hash key一致。
这样就可以保证,在一个机器上生成缓存,下次请求到另外一个机器,仍然可以使用这个缓存。
public static int deepHashCode(Object a[]) {
if (a == null)
return 0;
int result = 1;
for (Object element : a) {
int elementHash = 0;
if (element instanceof Object[])
elementHash = deepHashCode((Object[]) element);
else if (element instanceof byte[])
elementHash = hashCode((byte[]) element);
else if (element instanceof short[])
elementHash = hashCode((short[]) element);
else if (element instanceof int[])
elementHash = hashCode((int[]) element);
else if (element instanceof long[])
elementHash = hashCode((long[]) element);
else if (element instanceof char[])
elementHash = hashCode((char[]) element);
else if (element instanceof float[])
elementHash = hashCode((float[]) element);
else if (element instanceof double[])
elementHash = hashCode((double[]) element);
else if (element instanceof boolean[])
elementHash = hashCode((boolean[]) element);
else if (element instanceof class)
elementHash = hashCode((element.toString());
else if (element != null)
elementHash = element.hashCode();
result = 31 * result + elementHash;
}
return result;
}
这一句, else if (element instanceof class)
elementHash = hashCode((element.toString());
加上对class的判断,对class做toString就会在不同机器产生一样的calss了,所以生成的hashcode一样。缓存就不变了。