SpringBoot @Cacheable自定义KeyGenerator方式

目录
  • @Cacheable自定义KeyGenerator
    • 1. 概述
    • 2. MySimpleKey 类
    • 3. MyKeyGenerator 类
    • 4. 配置keyGenerator
  • Spring-Cache key设置
    • 第一种方式:手动设置
    • 第二种方式:自定义keyGenerator

@Cacheable自定义KeyGenerator

1. 概述

SpringBoot 使用 @Cacheable 可以方便的管理缓存数据,在不指定 key 属性的情况下,默认使用 SimpleKeyGenerator 生成 key。除此之外,我们也可以自定义实现 KeyGenerator 接口,生成自己的 key 名称策略。

2. MySimpleKey 类

MySimpleKey类的作用是存放参数数据,必须实现equals、hashCode。如果需要自定义key格式,同样需要实现toString接口,下面的例子是把参数用逗号分隔。

public class MySimpleKey implements Serializable {
    public static final MySimpleKey EMPTY = new MySimpleKey(new Object[0]);
    private final Object[] params;
    private transient int hashCode;
    public MySimpleKey(Object... elements) {
        Assert.notNull(elements, "Elements must not be null");
        this.params = (Object[])elements.clone();
        this.hashCode = Arrays.deepHashCode(this.params);
    }
    public boolean equals(@Nullable Object other) {
        return this == other || other instanceof MySimpleKey && Arrays.deepEquals(this.params, ((MySimpleKey)other).params);
    }
    public final int hashCode() {
        return this.hashCode;
    }
    public String toString() {
        return StringUtils.arrayToCommaDelimitedString(this.params);
    }
}

3. MyKeyGenerator 类

MyKeyGenerator 实现 KeyGenerator 的接口,里面只有一个 generate 方法

public class MyKeyGenerator implements KeyGenerator {
    @Override
    public Object generate(Object o, Method method, Object... objects) {
        if (objects.length == 0) {
            return MySimpleKey.EMPTY;
        } else {
            if (objects.length == 1) {
                Object param = objects[0];
                if (param != null && !param.getClass().isArray()) {
                    return param;
                }
            }
            return new MySimpleKey(objects);
        }
    }
}

定义MyKeyGenerator Bean:

@Component
public class MyRedisConf {
    @Bean
    public MyKeyGenerator myKeyGenerator(){
        return new MyKeyGenerator();
    }
}

4. 配置keyGenerator

在 @Cacheable 配置 keyGenerator 属性,值就是前面配置的Bean名称

    @Override
    @Cacheable(value = {"REDIS:GETSTRING3"}, keyGenerator = "myKeyGenerator")
    public String getString3(String tag, String name) {
        return tag + " " + name;
    }

测试结果如下,tag、name 参数确实以逗号分隔

127.0.0.1:6379[5]> KEYS *

1) "REDIS:GETSTRING3::hello,zhangsan"

Spring-Cache key设置

第一种方式:手动设置

为了便于key的不重复,我们可以手动设置key有类名、方法名、参数等组合

属性名称
描述


示例


methodName


当前方法名


#root.methodName


method


当前方法


#root.method.name


target


当前被调用的对象


#root.target


targetClass


当前被调用的对象的class


#root.targetClass


args


当前方法参数组成的数组


#root.args[0]


caches


当前被调用的方法使用的Cache


#root.caches[0].name

key = "#root.targetClass.simpleName+':'+#root.methodName+':'+#param"

如下图所示

第二种方式:自定义keyGenerator

1、自定义CacheKeyGenerator 实现KeyGenerator

public class CacheKeyGenerator implements KeyGenerator {
    /**
     * (非 Javadoc)
     * <p>
     * Title: generate
     * </p>
     *
     * @param target
     * @param method
     * @param params
     * @return
     * @see org.springframework.cache.interceptor.KeyGenerator#generate(java.lang.Object,
     *      java.lang.reflect.Method, java.lang.Object[])
     */
    @Override
    public Object generate(Object target, Method method, Object... params) {
        StringBuilder key = new StringBuilder();
        key.append(target.getClass().getSimpleName()).append(":").append(method.getName()).append(":");
        if (params.length == 0) {
            return key.toString();
        }
        for (int i = 0; i < params.length; i++) {
            Object param = params[i];
            if (param == null || param instanceof LogableParam) {
                del(key);
            } else if (ClassUtils.isPrimitiveArray(param.getClass())) {
                int length = Array.getLength(param);
                for (int j = 0; j < length; j++) {
                    key.append(Array.get(param, j));
                    key.append(',');
                }
            } else if (ClassUtils.isPrimitiveOrWrapper(param.getClass()) || param instanceof String) {
                key.append(param);
            } else {
                key.append(param.toString());
            }
            key.append('-');
        }
        del(key);
        return key.toString();
    }
    private StringBuilder del(StringBuilder stringBuilder) {
        if (stringBuilder.toString().endsWith("-")) {
            stringBuilder.deleteCharAt(stringBuilder.length() - 1);
        }
        return stringBuilder;
    }
}

2、配置xml

<cache:annotation-driven cache-manager="cacheManager" key-generator="cacheKeyGenerator"
        proxy-target-class="true" />
<bean id="cacheKeyGenerator" class="com.tensoon.util.CacheKeyGenerator"></bean>

3、配置注解

如下图所示

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Spring Boot集成redis,key自定义生成方式

    一)自定义redis key生成策略 @Configuration:表示当前类属于一个配置类,类似于一个spring.cfg.xml. @EnableCaching:表示支持启用缓存. 自定义配置源码: import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cach

  • 详解SpringBoot2.0的@Cacheable(Redis)缓存失效时间解决方案

    问题   @Cacheable注解不支持配置过期时间,所有需要通过配置CacheManneg来配置默认的过期时间和针对每个类或者是方法进行缓存失效时间配置. 解决   可以采用如下的配置信息来解决的设置失效时间问题 配置信息 @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { return new RedisCacheManager( RedisCacheWriter.no

  • Spring Boot 中使用cache缓存的方法

    一.什么是缓存 Cache Cache 一词最早来自于CPU设计 当CPU要读取一个数据时,首先从CPU缓存中查找,找到就立即读取并送给CPU处理:没有找到,就从速率相对较慢的内存中读取并送给CPU处理,同时把这个数据所在的数据块调入缓存中,可以使得以后对整块数据的读取都从缓存中进行,不必再调用内存.正是这样的读取机制使CPU读取缓存的命中率非常高(大多数CPU可达90%左右),也就是说CPU下一次要读取的数据90%都在CPU缓存中,只有大约10%需要从内存读取.这大大节省了CPU直接读取内存的

  • SpringBoot @Cacheable自定义KeyGenerator方式

    目录 @Cacheable自定义KeyGenerator 1. 概述 2. MySimpleKey 类 3. MyKeyGenerator 类 4. 配置keyGenerator Spring-Cache key设置 第一种方式:手动设置 第二种方式:自定义keyGenerator @Cacheable自定义KeyGenerator 1. 概述 SpringBoot 使用 @Cacheable 可以方便的管理缓存数据,在不指定 key 属性的情况下,默认使用 SimpleKeyGenerator

  • SpringBoot读取自定义配置文件方式(properties,yaml)

    目录 一.读取系统配置文件application.yaml 二.读取自定义配置文件properties格式内容 三.读取自定义配置文件yaml格式内容 四.其他扩展内容 一.读取系统配置文件application.yaml 1.application.yaml配置文件中增加一下测试配置 testdata: animal: lastName: 动物 age: 18 boss: true birth: 2022/02/22 maps: {key1:value1,key2:value2} list:

  • 在SpringBoot 中从application.yml中获取自定义常量方式

    要注意的地方是 application.yml 中不能用驼峰式写法(systemParams)要改成system-params 方法一: 引入依赖: <!-- 支持 @ConfigurationProperties 注解 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</a

  • springboot扫描自定义的servlet和filter代码详解

    这几天使用spring boot编写公司一个应用,在编写了一个filter,用于指定编码的filter,如下: /** * Created by xiaxuan on 16/11/1. */ @WebFilter(urlPatterns = "/*",filterName="CharacterEncodeFilter", initParams={ @WebInitParam(name="encoding",value="UTF-8&qu

  • SpringBoot通过自定义注解实现日志打印的示例代码

    前言 在我们日常的开发过程中通过打印详细的日志信息能够帮助我们很好地去发现开发过程中可能出现的Bug,特别是在开发Controller层的接口时,我们一般会打印出Request请求参数和Response响应结果,但是如果这些打印日志的代码相对而言还是比较重复的,那么我们可以通过什么样的方式来简化日志打印的代码呢? SpringBoot 通过自定义注解实现权限检查可参考我的博客:SpringBoot 通过自定义注解实现权限检查 正文 Spring AOP Spring AOP 即面向切面,是对OO

  • Springboot Druid 自定义加密数据库密码的几种方案

    前言 开发过程中,配置的数据库密码通常是明文形式,这样首先第一个安全性不好(相对来说),不符合一个开发规范(如项目中不能出现明文账号密码),其实就是当出现特殊需求时,比如要对非运维人员开方服务器部分权限,但是又涉及项目部署的目录时,容易泄漏数据库密码,虽然一般生产环境中,数据库往往放入内网,访问只能通过内网访问,但是不管怎么说账号密码直接让人知道总归不好,甚至有些项目需要部署到客户环境中,但是可能共用一个公共数据库(数据库只向指定服务器开放外网端口或组建内网环境),这样的情况下,如果数据库密码再

  • Prometheus 入门教程之SpringBoot 实现自定义指标监控

    上篇文章我们已经可以在 Grafana 上看到对应的 SpringBoot 应用信息了,通过这些信息我们可以对 SpringBoot 应用有更全面的监控.但是如果我们需要对一些业务指标做监控,我们应该怎么做呢?这篇文章就带你一步步实现一个模拟的订单业务指标监控. 假设我们有一个订单系统,我们需要监控它的实时订单总额.10 分钟内的下单失败率.请求失败数.那么我们应该怎么做呢? 添加业务监控指标 在 spring-web-prometheus-demo 项目的基础上,我们添加一个 Promethe

  • SpringBoot之自定义Banner详解

    1.在线生成banner网站 https://www.bootschool.net/ascii http://www.network-science.de/ascii/ http://patorjk.com/software/taag/ http://www.degraeve.com/img2txt.php 2.两种自定义Banner方式 在自定义Banner之前,先剖析一下源码,源码跟踪解析如下: SpringBoot启动的main方法 public static void main(Stri

  • SpringBoot如何自定义starter

    目录 1. 什么是starter 2. 自动配置原理 2.1 自动配置生效 3. 自定义starter 3.1 命名规范 4.总结 4.1为什么要自定义starter? 4.2 自定义starter的案例 1. 什么是starter Springboot的出现极大的简化了开发人员的配置,而这之中的一大利器便是springboot的starter,starter是springboot的核心组成部分,为什么说引入如下依赖就满足了日常web开发? <dependency>   <groupId

  • 详解如何在SpringBoot中自定义参数解析器

    目录 前言 1.自定义参数解析器 2.PrincipalMethodArgumentResolver 3.RequestParamMapMethodArgumentResolver 4.小结 前言 在一个 Web 请求中,参数我们无非就是放在地址栏或者请求体中,个别请求可能放在请求头中. 放在地址栏中,我们可以通过如下方式获取参数: String javaboy = request.getParameter("name "); 放在请求体中,如果是 key/value 形式,我们可以通

随机推荐