SpringBoot 集成 JetCache-Alibaba 实现本地缓存

目录

  • [1、JetCache 简介](#1、JetCache 简介)
  • [2、JetCache 核心概念](#2、JetCache 核心概念)
  • 3、入门案例
    • 3.1、引入依赖
    • 3.2、修改配置文件
    • 3.3、添加配置扫描注解
    • [3.4、使用 JetCache](#3.4、使用 JetCache)
      • 3.4.1、基于注解实现缓存
        • [3.4.1.1、添加 `UserServiceImpl`:](#3.4.1.1、添加 UserServiceImpl:)
        • [3.4.1.2、添加 `TestController`:](#3.4.1.2、添加 TestController:)
        • [3.4.1.1、`@Cached` 注解](#3.4.1.1、@Cached 注解)
        • [3.4.1.1.1、cacheType 属性](#3.4.1.1.1、cacheType 属性)
        • [3.4.1.2、`@CacheUpdate` 注解](#3.4.1.2、@CacheUpdate 注解)
        • [3.4.1.3、`@CacheInvalidate` 注解](#3.4.1.3、@CacheInvalidate 注解)
      • [3.4.2、基于 `@CreateCache` 注解实现缓存](#3.4.2、基于 @CreateCache 注解实现缓存)
      • [3.4.3、基于 API 方式实现缓存](#3.4.3、基于 API 方式实现缓存)
        • [3.4.3.1、添加一个配置类 `JetcacheConfig`:](#3.4.3.1、添加一个配置类 JetcacheConfig:)
        • [3.4.3.2、添加 `TestController`](#3.4.3.2、添加 TestController)

1、JetCache 简介

官网地址
官方文档

JetCache 是由阿里巴巴开源的一款基于 Spring 和 Redis 的分布式缓存框架 ,提供统一的 API 和注解来简化缓存的使用。

JetCache 提供了比 Spring Cache更加强大的注解,可以原生的支持 TTL、两级缓存、分布式自动刷新,还提供了 Cache 接口用于手工缓存操作。 当前有四个实现,RedisCacheTairCache(此部分未在 github 开源)、CaffeineCache(in memory) 和一个简易的 LinkedHashMapCache (in memory),要添加新的实现也是非常简单的

它的特性:

  • 通过统一的 API 访问 Cache 系统
  • 通过注解实现声明式的方法缓存,支持 TTL 和两级缓存
  • 通过注解创建并配置 Cache 实例
  • 针对所有 Cache 实例和方法缓存的自动统计
  • Key 的生成策略和 Value 的序列化策略是可以配置的
  • 分布式缓存自动刷新,分布式锁 (2.2+)
  • 异步 Cache API (2.2+,使用 Redis 的 lettuce 客户端时)

2、JetCache 核心概念

  • 缓存抽象JetCache-Alibaba 提供了一个统一的缓存抽象层,这意味着你不需要直接和具体的缓存实现打交道。它为你封装好了底层的细节,你只需要通过它提供的 API 来操作缓存即可。这样一来,你更换缓存实现的时候,就不需要改动大量的代码了
  • 分布式缓存 : 在分布式系统中,应用可能部署在多台机器上。这时候,如果每台机器都有自己的本地缓存,那数据就不一致了。JetCache-Alibaba 支持分布式缓存,它能确保多台机器上的缓存数据是一致的。这样,无论你的应用部署在哪里,都能读到正确的缓存数据
  • 缓存一致性 : 缓存里的数据和数据库里的数据得保持一致。JetCache-Alibaba 提供了多种策略来确保缓存的一致性,比如缓存失效、缓存更新等。根据自己的业务场景来选择合适的策略
  • 降级策略 : 有时候,缓存可能会失效或者出点什么问题。这时候,应用可不能直接崩溃。JetCache-Alibaba 提供了降级策略,当缓存不可用时,它会自动切换到数据库或者其他备份数据源,确保你的应用依然能够正常运行

3、入门案例

3.1、引入依赖

https://github.com/alibaba/jetcache/blob/master/docs/CN/GettingStarted.md

xml 复制代码
<dependency>
    <groupId>com.alicp.jetcache</groupId>
    <artifactId>jetcache-starter-redis</artifactId>
    <version>2.7.3</version>
</dependency>
<!-- jedis  -->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>4.3.0</version>
</dependency>

这里使用了 Jedis 客户端连接 Redis

注意,如果启动出现 NoClassDefFoundError: redis/clients/util/PoolNoClassDefFoundError: redis/clients/jedis/UnifiedJedis 报错,说明 springboot 与 jetcache 版本不一致。如果使用的是jetcache2.7.x 版本,因为该版本中有 jedis 包的依赖,需要额外添加如下依赖,或者将 jetcache 版本将至 2.6.5 以下

3.2、修改配置文件

更详细的参数配置可参考官网说明:https://gitcode.com/gh_mirrors/je/jetcache/blob/master/docs/CN/Config.md

yml 复制代码
jetcache:
  # 统计间隔 0 表示不统计
  statIntervalMinutes: 15
  # 是否在缓存名称中包含 area。
  # jetcache-anno 把 cacheName 作为远程缓存 key 前缀,2.4.3 以前的版本总是把 areaName 加在 cacheName 中,因此 areaName 也出现在 key 前缀中。
  # 2.4.4以后可以配置,为了保持远程 key 兼容默认值为 true,但是新项目的话 false 更合理些,2.7 默认值已改为 false。
  areaInCacheName: false
  # 缓存类型。local 本地缓存;remote 远程缓存;local+remote 本地+远程缓存
  # 本地缓存:caffeine、linkedhashmap
  # 远程缓存:redis、tair
  local:
    # area:默认缓存配置。对应 @Cached 和 @CreateCache 的 area 属性
    default:
      # 本地缓存类型
      type: caffeine
      # key 转换器:fastjson、fastjson2、jackson
      # 仅当使用 @CreateCache 且缓存类型为 local 时可以指定为 none,此时通过 equals 方法来识别 key。方法缓存必须指定 keyConvertor
      keyConvertor: JACKSON
      # 每个缓存实例的最大元素的全局配置,仅 local 类型的缓存需要指定
      limit: 100
      # 缓存过期时间,单位毫秒
      expireAfterWriteInMillis: 100000
      # 指定多长时间没有访问,就让缓存失效,当前只有本地缓存支持  以毫秒为单位;0 表示不使用这个功能
      expireAfterAccessInMillis: 100000
  # 远程缓存配置
  remote:
    default:
      # 远程缓存类型
      type: redis
      keyConvertor: JACKSON
      # 配置远程缓存的广播通道,通常用于分布式环境中实现缓存同步
      #broadcastChannel: myBroadcastChannel
      # 2.7+可选java/kryo/kryo5;2.6-可选java/kryo
      valueEncoder: java
      # 2.7+可选java/kryo/kryo5;2.6-可选java/kryo
      valueDecoder: java
      # redis 线程池
      poolConfig:
        minIdle: 5
        maxIdle: 20
        maxTotal: 50
      host: 127.0.0.1
      port: 6379

3.3、添加配置扫描注解

启动类添加注解 @EnableCreateCacheAnnotation,开启缓存;添加@EnableMethodCache(basePackages = "com.zzc") 注解,配置缓存方法扫描路径

java 复制代码
@EnableCreateCacheAnnotation
@EnableMethodCache(basePackages = "com.zzc")
@SpringBootApplication
public class Test2Application {

    public static void main(String[] args) {
        SpringApplication.run(Test2Application.class, args);
    }
}

3.4、使用 JetCache

3.4.1、基于注解实现缓存

https://gitcode.com/gh_mirrors/je/jetcache/blob/master/docs/CN/MethodCache.md

JetCache 方法缓存和 Spring Cache比较类似,它原生提供了 TTL 支持,以保证最终一致,并且支持二级缓存。JetCache2.4 以后支持基于注解的缓存更新和删除。

在 Spring 环境下,使用 @Cached 注解可以为一个方法添加缓存,@CacheUpdate 用于更新缓存,@CacheInvalidate用于移除缓存元素。注解可以加在接口上也可以加在类上,加注解的类必须是一个Spring Bean。

3.4.1.1、添加 UserServiceImpl
java 复制代码
@Slf4j
@Service
public class UserServiceImpl {

    // 模拟数据库数据
    private Map<Integer, User> userMap = new HashMap<>();

    @Cached(name = "userCache:", key = "#user.id", expire = 3600, timeUnit = TimeUnit.SECONDS, cacheType = CacheType.LOCAL)
    public User add(User user) {
        log.info("add");
        userMap.put(user.getId(), user);
        return user;
    }

    @Cached(name = "userCache:", key = "#id", expire = 3600, timeUnit = TimeUnit.SECONDS, cacheType = CacheType.LOCAL)
    public User get(Integer id) {
        log.info("get");
        return userMap.get(id);
    }

    @CacheUpdate(name = "userCache:", key = "#user.id", value = "#user")
    public User update(User user) {
        log.info("update");
        userMap.put(user.getId(), user);
        return user;
    }

    @CacheInvalidate(name = "userCache:", key = "#id")
    public void delete(Integer id) {
        log.info("delete");
        userMap.remove(id);
    }

}
3.4.1.2、添加 TestController
java 复制代码
@RestController
public class TestController {

    @Autowired
    private UserServiceImpl userServiceImpl;

    @PostMapping
    public String add(@RequestBody User user) {
        userServiceImpl.add(user);
        return "add";
    }

    @GetMapping("/{id}")
    public User get(@PathVariable Integer id) {
        User user = userServiceImpl.get(id);
        return user;
    }

    @PutMapping
    public String update(@RequestBody User user) {
        userServiceImpl.update(user);
        return "update";
    }

    @DeleteMapping("/{id}")
    public String delete(@PathVariable Integer id) {
        userServiceImpl.delete(id);
        return "delete";
    }

}

@CacheUpdate@CacheInvalidate 的 name 和 area 属性必须和 @Cached` 相同,name 属性还会用做 cache 的 key 前缀

3.4.1.1、@Cached 注解

@Cached 注解的属性如下:

属性 默认值 说明
area "default" 如果在配置中配置了多个缓存 area,在这里指定使用哪个 area
name 指定缓存的唯一名称,不是必须的,如果没有指定,会使用类名+方法名。name 会被用于远程缓存的 key 前缀。另外在统计中,一个简短有意义的名字会提高可读性。
key 使用 SpEL 指定 key,如果没有指定会根据所有参数自动生成
expire 超时时间。如果注解上没有定义,会使用全局配置,如果此时全局配置也没有定义,则为无穷大
timeUnit TimeUnit.SECONDS 指定 expire 的单位
cacheType CacheType.REMOTE 缓存的类型,包括 CacheType.REMOTE、CacheType.LOCAL、CacheType.BOTH。如果定义为 BOTH,会使用 LOCAL 和 REMOTE 组合成两级缓存
localLimit 如果 cacheType 为 LOCAL 或 BOTH,这个参数指定本地缓存的最大元素数量,以控制内存占用。如果注解上没有定义,会使用全局配置,如果此时全局配置也没有定义,则为 100
localExpire 仅当 cacheType 为 BOTH 时适用,为内存中的 Cache 指定一个不一样的超时时间,通常应该小于 expire
serialPolicy 指定远程缓存的序列化方式。可选值为 SerialPolicy.JAVA 和 SerialPolicy.KRYO。如果注解上没有定义,会使用全局配置,如果此时全局配置也没有定义,则为 SerialPolicy.JAVA
keyConvertor 指定 KEY 的转换方式,用于将复杂的 KEY 类型转换为缓存实现可以接受的类型,当前支持KeyConvertor.FASTJSON 和 KeyConvertor.NONE。NONE 表示不转换,FASTJSON 可以将复杂对象 KEY 转换成 String。如果注解上没有定义,会使用全局配置
enabled true 是否激活缓存。例如某个 dao 方法上加缓存注解,由于某些调用场景下不能有缓存,所以可以设置 enabled 为 false,正常调用不会使用缓存,在需要的地方可使用 CacheContext.enableCache 在回调中激活缓存,缓存激活的标记在 ThreadLocal 上,该标记被设置后,所有 enable=false 的缓存都被激活
cacheNullValue false 当方法返回值为null的时候是否要缓存
condition 使用 SpEL 指定条件,如果表达式返回 true 的时候才去缓存中查询
postCondition 使用 SpEL 指定条件,如果表达式返回 true 的时候才更新缓存,该评估在方法执行后进行,因此可以访问到 #result
3.4.1.1.1、cacheType 属性

可以指定本地缓存、远程缓存、本地缓存 + 远程缓存。

java 复制代码
@Cached(name = "userCache:", key = "#user.id", expire = 3600, timeUnit = TimeUnit.SECONDS, cacheType = CacheType.REMOTE)
public User add(User user) {
    log.info("add");
    userMap.put(user.getId(), user);
    return user;
}

此时,User 需要实现 Serializable 接口

多级缓存的形式,会先从本地缓存获取数据,本地获取不到会从远程缓存获取;

3.4.1.2、@CacheUpdate 注解

@CacheUpdate 注解的属性如下:

属性 默认值 说明
area "default" 如果在配置中配置了多个缓存 area,在这里指定使用哪个 area
name 指定缓存的唯一名称,不是必须的,如果没有指定,会使用类名+方法名。name 会被用于远程缓存的 key 前缀。另外在统计中,一个简短有意义的名字会提高可读性。
key 使用 SpEL 指定 key,如果没有指定会根据所有参数自动生成
value 使用 SpEL 指定 value
condition 使用 SpEL 指定条件,如果表达式返回 true 的时候才去缓存中查询
3.4.1.3、@CacheInvalidate 注解

@CacheInvalidate 注解的属性如下:

属性 默认值 说明
area "default" 如果在配置中配置了多个缓存 area,在这里指定使用哪个 area
name 指定缓存的唯一名称,不是必须的,如果没有指定,会使用类名+方法名。name 会被用于远程缓存的 key 前缀。另外在统计中,一个简短有意义的名字会提高可读性。
key 使用 SpEL 指定 key,如果没有指定会根据所有参数自动生成
condition 使用 SpEL 指定条件,如果表达式返回 true 的时候才去缓存中查询

使用 @CacheUpdate@CacheInvalidate 的时候,相关的缓存操作可能会失败(比如网络 IO 错误),所以指定缓存的超时时间是非常重要的

3.4.2、基于 @CreateCache 注解实现缓存

jetcache 2.7 版本 @CreateCache 注解已经废弃

3.4.3、基于 API 方式实现缓存

通过 CacheManager,2.7 版本才可使用

https://github.com/alibaba/jetcache/blob/master/docs/CN/CreateCache.md

使用 CacheManager 可以创建 Cache 实例,area 和 name 相同的情况下,它和 Cached 注解使用同一个 Cache 实例

3.4.3.1、添加一个配置类 JetcacheConfig
java 复制代码
@Configuration
public class JetcacheConfig {

    @Autowired
    private CacheManager cacheManager;
    private Cache<Integer, Object> userCache;

    @PostConstruct
    public void init(){
        QuickConfig qc = QuickConfig.newBuilder("userCache:")
                .expire(Duration.ofSeconds(3600))
                .cacheType(CacheType.BOTH)
                // 本地缓存更新后,将在所有的节点中删除缓存,以保持强一致性
                .syncLocal(false)
                .build();
        userCache = cacheManager.getOrCreateCache(qc);
    }

    @Bean
    public Cache<Integer, Object> getUserCache(){
        return userCache;
    }
}
3.4.3.2、添加 TestController
java 复制代码
@RestController
public class TestController {

    @Autowired
    private Cache<Integer, Object> userCache;

    @PostMapping
    public String add(@RequestBody User user) {
        userCache.put(user.getId(), user);
        return "add";
    }

    @GetMapping("/{id}")
    public User get(@PathVariable Integer id) {
        User user = (User) userCache.get(id);
        return user;
    }

    @PutMapping
    public String update(@RequestBody User user) {
        userCache.put(user.getId(), user);
        return "update";
    }

    @DeleteMapping("/{id}")
    public String delete(@PathVariable Integer id) {
        userCache.remove(id);
        return "delete";
    }
}
相关推荐
xujiangyan_2 小时前
Redis详解
数据库·redis·缓存
摇滚侠3 小时前
Spring Boot 3零基础教程,IOC容器中组件的注册,笔记08
spring boot·笔记·后端
程序员小凯5 小时前
Spring Boot测试框架详解
java·spring boot·后端
你的人类朋友6 小时前
什么是断言?
前端·后端·安全
程序员小凯7 小时前
Spring Boot缓存机制详解
spring boot·后端·缓存
i学长的猫7 小时前
Ruby on Rails 从0 开始入门到进阶到高级 - 10分钟速通版
后端·ruby on rails·ruby
用户21411832636028 小时前
别再为 Claude 付费!Codex + 免费模型 + cc-switch,多场景 AI 编程全搞定
后端
茯苓gao8 小时前
Django网站开发记录(一)配置Mniconda,Python虚拟环境,配置Django
后端·python·django
Cherry Zack8 小时前
Django视图进阶:快捷函数、装饰器与请求响应
后端·python·django
程序媛徐师姐8 小时前
Java基于SpringBoot的茶叶商城系统,附源码+文档说明
java·spring boot·java springboot·茶叶商城系统·java茶叶商城系统·茶叶·java茶叶商城