Springboot 2.0.x Redis缓存Key生成器,自定义生成器

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_15071263/article/details/84335632

Springboot 2.0.x Redis缓存Key生成器,自定义生成器


1、默认的Key生成策略

首先看看生成器接口的源码


package org.springframework.cache.interceptor;

import java.lang.reflect.Method;

/**
 * Cache key generator. Used for creating a key based on the given method
 * (used as context) and its parameters.
 *
 * @author Costin Leau
 * @author Chris Beams
 * @author Phillip Webb
 * @since 3.1
 */
@FunctionalInterface
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);

}



然后看默认的Key 生成策略


package org.springframework.cache.interceptor;

import java.lang.reflect.Method;

/**
 * Simple key generator. Returns the parameter itself if a single non-null
 * value is given, otherwise returns a {@link SimpleKey} of the parameters.
 *
 * <p>No collisions will occur with the keys generated by this class.
 * The returned {@link SimpleKey} object can be safely used with a
 * {@link org.springframework.cache.concurrent.ConcurrentMapCache}, however,
 * might not be suitable for all {@link org.springframework.cache.Cache}
 * implementations.
 *
 * @author Phillip Webb
 * @author Juergen Hoeller
 * @since 4.0
 * @see SimpleKey
 * @see org.springframework.cache.annotation.CachingConfigurer
 */
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) {
			// 如果没有参数,就构建一个new Object[] 作为参数
			return SimpleKey.EMPTY;
		}
		if (params.length == 1) {
			Object param = params[0];
			if (param != null && !param.getClass().isArray()) {
				return param;
			}
		}
		return new SimpleKey(params);
	}

}

然后是SimpleKey 的源码

	/**
	 * Create a new {@link SimpleKey} instance.
	 * @param elements the elements of the key
	 */
	public SimpleKey(Object... elements) {
		// 首先断言,参数列表不是null,否则抛出 IllegalArgumentException
		Assert.notNull(elements, "Elements must not be null");
		this.params = new Object[elements.length];
		// 组装参数作为Key
		System.arraycopy(elements, 0, this.params, 0, elements.length);
		this.hashCode = Arrays.deepHashCode(this.params);
	}

一般情况下,默认的Key生成策略,如果不同的包存在相同的参数列表和传递了相同的参数值,则在一定条件下,会导致访问到错误的缓存。所以我们重写生成器,来避免这个问题

2、重写生成器
import com.alibaba.fastjson.JSON;
import com.zyfycs.college.core.ModelContainer;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.cache.interceptor.KeyGenerator;

import java.lang.reflect.Method;

/**
 * @author Created by 谭健 on 2018/11/21. 星期三. 14:53.
 * © All Rights Reserved.
 */

public class RedisCacheKeyGenerator implements KeyGenerator {
    @Override

    public Object generate(Object targetClass, Method method, Object... params) {
	// 这里可用HashMap
        ModelContainer<String,Object> container = ModelContainer.newModelContainer();
        Class<?> targetClassClass = targetClass.getClass();
        // 类地址
        container.put("class",targetClassClass.toGenericString());
        // 方法名称
        container.put("methodName",method.getName());
        // 包名称
        container.put("package",targetClassClass.getPackage());
        // 参数列表
        for (int i = 0; i < params.length; i++) {
            container.put(String.valueOf(i),params[i]);
        }
        // 转为JSON字符串
        String jsonString = JSON.toJSONString(container);
        // 做SHA256 Hash计算,得到一个SHA256摘要作为Key
        return DigestUtils.sha256Hex(jsonString);
    }
}

DigestUtils 包

<dependency>
			<groupId>commons-codec</groupId>
			<artifactId>commons-codec</artifactId>
</dependency>
3、注册自定义生成器
	// 在 CacheConfig 中定义
    @Bean
    KeyGenerator keyGenerator(){
        return new RedisCacheKeyGenerator();
    }

	// 该值是 keyGenerator 方法的方法名称,如果Bean 指定了名称,则使用指定的名称
	public static final String DEFAULT_KEY_GENERATOR = "keyGenerator";
	
	// 定义缓存区,缓存区可以在配置时指定不同的过期时间,作为防止缓存雪崩的一个保护措施
	public static final String COMMON = "COMMON";
4、应用
@Cacheable(value = CacheConfig.COMMON,keyGenerator = CacheConfig.DEFAULT_KEY_GENERATOR)
5、在Redis 中Key的显示
COMMON::b525f46bc5dac06113cb9a3a9c094231db3a20dcd89bf36edebfd14ae9ee1500

猜你喜欢

转载自blog.csdn.net/qq_15071263/article/details/84335632