Spring Cache的基本使用以及工作原理 (学习记录)

160 阅读4分钟

目标:学会使用SpringCache查询缓存注解并理解它的原理

背景

Redis访问工具

项目使用Redis存储缓存数据,如何通过Java去访问Redis?

常用的有JedisLettuce两个访问redis的客户端库,其中Lettuce的性能和并发性要好一些,Spring Boot 默认使用的是 Lettuce 作为 Redis 的客户端。

集成Spring data redis框架,在项目中可以通过RedisTemplate访问Redis,RedisTemplate提供了方便访问redis的模板方法。

Spring Cache最终也是通过Lettuce 去访问redis 。

使用Spring Cache的方法很简单,只需要在方法上添加注解即可实现将方法返回数据存入缓存,以及清理缓存等注解的使用。

Spring Cache基本介绍

Spring Cache是Spring提供的一个缓存框架,基于AOP原理,实现了基于注解的缓存功能,只需要简单地加一个注解就能实现缓存功能,对业务代码的侵入性很小

基于SpringBoot使用Spring Cache非常简单,首先加入依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
    <version>2.7.10</version>
</dependency>
简单认识它的常用注解:
@EnableCaching:开启缓存注解功能
@Cacheable:查询数据时缓存,将方法的返回值进行缓存
@CacheEvict:用于删除缓存,将一条或多条数据从缓存中删除
@CachePut:用于更新缓存,将方法的返回值放到缓存中
@Caching:组合多个缓存注解
@CacheConfig:统一配置@Cacheable中的value值

查询数据时缓存@Cacheable:

下边使用Cacheable注解实现查询服务信息时对服务信息进行缓存,它的执行流程是:第一次查询服务信息缓存中,没有该服务的信息此时去查询数据库,查询数据库拿到服务信息并进行缓存,第二次再去查询该服务信息,发现缓存中有该服务的信息, 则直接查询缓存不再去数据库查询。

流程如下:

image.png

1.首先在工程启动类中添加@EnableCaching注解,它表示开启Spring cache缓存组件。

image.png

2.在IServeService接口中定义如下接口:

/**
 * 查询区域服务信息并进行缓存
 * @param id 对应serve表的主键
 * @return 区域服务信息
 */
Serve queryServeByIdCache(Long id);

3.在接口实现类中定义如下方法:

@Override
public Serve queryServeByIdCache(Long id) {
    return getById(id);
}

此时该方法还是查询数据库。

下边在方法中添加Cacheable注解:

 //    @Cacheable(value = "JZ_CACHE:SERVE_RECORD",key = "#id")
    @Cacheable(value = RedisConstants.CacheName.SERVE,key = "#id")
    public Serve queryServeByIdCache(Long id) {
        return getById(id);
    }

Cacheable注解配置的两项参数说明:

value:缓存的名称,缓存名称作为缓存key的前缀。

key: 缓存key,支持SpEL表达式,上述代码表示取参数id的值作为key

最终缓存key为:缓存名称+“::”+key,例如:上述代码id为123,最终的key为:测试 JZ_CACHE:SERVE_RECORD::123

SpEL(Spring Expression Language)是一种在 Spring 框架中用于处理字符串表达式的强大工具,它可以实现获取对象的属性,调用对象的方法操作。

keyGenerator:指定一个自定义的键生成器(实现 org.springframework.cache.interceptor.KeyGenerator 接口的类),用于生成缓存的键。与 key 属性互斥,二者只能选其一。

4.测试

image.png

测试@CachePut

CachePut注解实现的是将方法的返回值放到缓存中。

在服务上架后会将区域服务的信息写入缓存,服务下架会从缓存删除,下边我们实现服务上架将服务写入缓存。

找到服务上架的方法,在方法上添加@CachePut注解:

@Override
@Transactional
@CachePut(value = RedisConstants.CacheName.SERVE, key = "#id",  cacheManager = RedisConstants.CacheManager.ONE_DAY)
public Serve onSale(Long id){
....

上边代码同样指定了缓存名称、缓存key及缓存管理器(缓存过期时间为一天)。

编写单元测试方法测试服务上架方法。

找一个草稿或下架状态的服务执行上架操作,也可以在serve表中找一个测试数据更改状态为0。

//服务上架测试
@Test
public void test_onSale(){
    //从serve表找一条下架的服务(sale_status  '售卖状态,0:草稿,1下架,2上架',)
    Serve serve = serveService.onSale(1715263395009191938L);
    Assert.notNull(serve,"服务为空");
}

测试@CacheEvict

下边测试服务下架删除缓存。

找到服务下架的方法,添加@CacheEvict注解

@Override
@Transactional
@CacheEvict(value = RedisConstants.CacheName.SERVE, key = "#id")
public Serve offSale(Long id){
....

工作原理

Spring Cache是基于AOP原理,对添加注解 @Cacheable 的类生成代理对象,在方法执行前查看是否有缓存对应的数据,如果有直接返回数据,如果没有调用源方法获取数据返回,并缓存起来,下边跟踪Spring Cache的切面类CacheAspectSupport.java中的private Object execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts)方法。 如下图:

image.png