Spring Cache简化缓存开发

简介: Spring Cache简化缓存开发

1 背景介绍

官方入门文档:https://spring.io/guides/gs/caching/


Spring 从3.1 开始定义了org.springframework.cache.Cache和org.springframework.cache.CacheManager 接口来统一不同的缓存技术; 并支持使用JCache(JSR-107)注解简化我们开发;Cache 接口为缓存的组件规范定义,包含缓存的各种操作集合; Cache 接口下Spring 提供了各种xxxCache 的实现;如RedisCache , EhCacheCache , ConcurrentMapCache 等;

每次调用需要缓存功能的方法时,Spring 会检查检查指定参数的指定的目标方法是否已 经被调用过;如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法并缓存结果后返回给用户。下次调用直接从缓存中获取。


如果我们的程序想要使用缓存,就要与这些框架耦合。聪明的架构师已经在利用接口来降低耦合了,利用面向对象的抽象和多态的特性,做到业务代码与具体的框架分离。

但我们仍然需要显式地在代码中去调用与缓存有关的接口和方法,在合适的时候插入数据到缓存里,在合适的时候从缓存中读取数据。

想一想AOP的适用场景,这不就是天生就应该AOP去做的吗?

是的,Spring Cache就是一个这个框架。它利用了AOP,实现了基于注解的缓存功能,并且进行了合理的抽象,业务代码不用关心底层是使用了什么缓存框架,只需要简单地加一个注解,就能实现缓存功能了。而且Spring Cache也提供了很多默认的配置,用户可以3秒钟就使用上一个很不错的缓存功能。

既然有这么好的轮子,干嘛不用呢?


2 使用方式

Spring cache提供了开箱即用的接入方式,只需要若干注解和缓存管理类即可接入.

1.开启缓存能力

引入缓存依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
    <version>2.1.3.RELEASE</version>
</dependency>

在应用启动类添加@EnableCaching注解:

@SpringBootApplication
@EnableCaching
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

2.使用缓存

在业务方法添加@Cacheable注解:

@Cacheable(cacheNames = {"task"})
public TaskInfoDTO getTask(String taskId) {
    log.info("TestBuzz.getTask mock query from DB......");
    TaskInfoDTO taskInfoDTO = new TaskInfoDTO();
    taskInfoDTO.setTaskId(taskId);
    taskInfoDTO.setApplicantId("system");
    taskInfoDTO.setDescription("test");
    return taskInfoDTO;
}

模拟请求:

@GetMapping("/test_cache")
public IResp<TaskInfoDTO> testCache() {
    TaskInfoDTO taskInfoDTO = this.testBuzz.getTask("task123");
    return IResp.getSuccessResult(taskInfoDTO);
}

连续发送两次查询请求:

curl http://localhost:port/test_cache

从日志中看到只打印了一次DB调用,也就是说明第二次走了缓存。就这么简单我们就开启并使用了spring的缓存能力。

3 常用注解

原理:基于Proxy/AspectJ动态代理技术的AOP思想(面向切面编程)

使用:


SpringCache包含两个顶级接口,Cache(缓存)和CacheManager(缓存管理器),顾名思义,用CacheManager去管理一堆Cache。

spring cache实现有基于XML/注解实现AOP;

CacheManager负责对缓存的增删改查, CacheManager的缓存的介质可配置, 如:ConcurrentMap/EhCache/Redis等。当没有加入EhCache或者Redis依赖时默认采用concurrentMap实现的缓存,是存在内存中,重启服务器则清空缓存

pring Cache中的注解主要有如下五个:


@Cacheable:缓存数据或者获取缓存数据

@CachePut:修改缓存数据

@CacheEvict: 清空缓存

@CacheConfig:统一配置@Cacheable中的value值

@Caching:组合多个Cache注解

3.1 @Cacheable

先从value中获取为key的缓存,如果存在直接返回;如果不存在则执行方法并返回,且把返回输出存入缓存。(注意:保存的数据是return返回的数据)

主要有三个参数:


value:缓存的名称,可以多个 (必填,也可以用@CacheConfig替代)

 @Cacheable(value="testcache")
 @Cacheable(value={"testcache1","testcache2"}
  • key:缓存的 key,按照 SpEL 表达式编写,为空时默认为方法的入参(value相当于缓存空间的名称,而key相当于是一个缓存值的名字)
@Cacheable(value="testcache",key="#id")
  • condition:缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false
@Cacheable(value="testcache",condition="#id.length()>2")

3.2 @CachePut

根据value中获取为key的缓存,如果存在则修改;不存在则新增

主要是三个参数

value,key,condition如上所示。

注意:保存的数据是return返回的数据,如下返回的有user对象和null,第一个缓存的数据是实体类,第二个缓存的数据是空

3.3 @CacheEvict

根据对应的value和key删除缓存,没有key值则删除value中所有的缓存

主要有五个参数value,key,condition,allEntries,beforeInvocation

  • allEntries:是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存
@CachEvict(value="testcache",allEntries=true)

图一、会清空getData下面所有缓存(allEntries=true则删除所有)

图二、只会清空getData下面key值为id的缓存(没有key默认取入参)

图三、不会清空任何缓存

  • beforeInvocation: 是否在方法执行前就清空,缺省为 false,如果指定为
    true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存(注:作用只有一个,就是先清空缓存再执行方法
@CachEvict(value="testcache",beforeInvocation=true)

3.4 @CacheConfig

相当于把类下面所有方法@Cacheable中的value值放到@CacheConfig注解中,

如果@Cacheable中没有value值则用@Cacheable中的值;如果@Cacheable中有value值则以value值为准。

@CacheConfig("testcache")
public class UserServiceImpl implements  UserService{
    @Cacheable
    public Result findById(Long id) {
    }
  @Cacheable
    public Result findByIdAndName(Long id,String name) {
    }

3.5 @Caching

组合注解,可以组合多个注解

@Caching(put = {
  @CachePut(value = "user", key = "#user.id"),
  @CachePut(value = "user", key = "#user.username"),
  @CachePut(value = "user", key = "#user.email")
})
public User save(User user) {
}

4 实战:Spring Cache整合redis缓存

4.1 CacheManager 缓存管理器

public interface CacheManager {
  //根据缓存名字获取缓存
  @Nullable
  Cache getCache(String name);
  //获取管理的所有缓存的名字
  Collection<String> getCacheNames();
}

支持多种类型的缓存

这里我们使用redis作为缓存

<!--    引入redis    -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.lettuce</groupId>
                    <artifactId>lettuce-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--   jedis不写版本springboot控制     -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>

4.2 配置spring-boot-starter-cache

1.缓存的自动配置

CacheProperties封装了配置文件中可以配置的属性

@ConfigurationProperties(prefix = "spring.cache")
org.springframework.boot.autoconfigure.cache.CacheProperties
CacheConfiguration`会根据缓存类型导入`RedisCacheConfiguration

RedisCacheConfiguration自动配好了缓存管理器

@Bean
  public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory,
      ResourceLoader resourceLoader) {
    RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory)
        .cacheDefaults(determineConfiguration(resourceLoader.getClassLoader()));
    List<String> cacheNames = this.cacheProperties.getCacheNames();
    if (!cacheNames.isEmpty()) {
      builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
    }
    return this.customizerInvoker.customize(builder.build());
  }

4.3 手动配置

配置使用Redis作为缓存

spring:
    cache:
      #cache-names: 可以自动配置
      type: redis

4.4 开启缓存功能 @Cacheable({“…”})

在启动类添加@EnableCaching 注解,不需要重复配Redis

@EnableCaching 注解

2.使用注解 就能完成缓存操作

//每一个需要缓存的数据都需要指定要放到哪个名字的缓存,缓存的分区,按照业务类型分 
 @Cacheable({"categroy"})    //代表方法的结果需要缓存 ,如果缓存中有 方法都不用调用,如果缓存中没有,调用方法,将结果放入缓存
 @Override
 public List<CategoryEntity> getLevel1Categorys() {
     long l = System.currentTimeMillis();
     List<CategoryEntity> categoryEntityList = baseMapper.selectList(new QueryWrapper<CategoryEntity>().eq("parent_cid", 0));
     System.out.println("消耗时间:" + (System.currentTimeMillis() - l));
     return categoryEntityList;
 }

使用@Cacheable 默认行为

如果缓存中有缓存 方法都不用调用

key值 自动生成

缓存的Value值默认使用JDK序列化机制,将序列化后的数据存到Redis

默认过期时间TTL -1 永不过去

应该要指定缓存存活时间 在配置文件中修改

  cache:
    #cache-names: 可以自动配置
    type: redis
    redis:
      time-to-live: 3600000  #设置存活时间毫秒
      key-prefix: CACHE_    #key前缀 如果制定了前缀就用指定的前缀,如果没有就默认使用缓存的名字作为前缀
      use-key-prefix: true  # 是否使用前缀
      cache-null-values: true # 是否缓存控制 解决缓存穿透


目录
相关文章
|
9月前
|
人工智能 运维 Java
Spring AI Alibaba Admin 开源!以数据为中心的 Agent 开发平台
Spring AI Alibaba Admin 正式发布!一站式实现 Prompt 管理、动态热更新、评测集构建、自动化评估与全链路可观测,助力企业高效构建可信赖的 AI Agent 应用。开源共建,现已上线!
8297 121
|
11月前
|
前端开发 Java API
利用 Spring WebFlux 技术打造高效非阻塞 API 的完整开发方案与实践技巧
本文介绍了如何使用Spring WebFlux构建高效、可扩展的非阻塞API,涵盖响应式编程核心概念、技术方案设计及具体实现示例,适用于高并发场景下的API开发。
747 0
|
9月前
|
安全 前端开发 Java
《深入理解Spring》:现代Java开发的核心框架
Spring自2003年诞生以来,已成为Java企业级开发的基石,凭借IoC、AOP、声明式编程等核心特性,极大简化了开发复杂度。本系列将深入解析Spring框架核心原理及Spring Boot、Cloud、Security等生态组件,助力开发者构建高效、可扩展的应用体系。(238字)
|
10月前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
1792 5
|
10月前
|
存储 缓存 Java
Spring中@Cacheable、@CacheEvict以及其他缓存相关注解的实用介绍
缓存是提升应用性能的重要技术,Spring框架提供了丰富的缓存注解,如`@Cacheable`、`@CacheEvict`等,帮助开发者简化缓存管理。本文介绍了如何在Spring中配置缓存管理器,使用缓存注解优化数据访问,并探讨了缓存的最佳实践,以提升系统响应速度与可扩展性。
449 0
Spring中@Cacheable、@CacheEvict以及其他缓存相关注解的实用介绍
|
11月前
|
缓存 监控 Linux
Linux系统清理缓存(buff/cache)的有效方法。
总结而言,在大多数情形下你不必担心Linux中buffer与cache占用过多内存在影响到其他程序运行;因为当程序请求更多内存在没有足够可用资源时,Linux会自行调整其占有量。只有当你明确知道当前环境与需求并希望立即回收这部分资源给即将运行重负载任务之前才考虑上述方法去主动干预。
2586 10
|
10月前
|
安全 数据可视化 Java
AiPy开发的 Spring 漏洞检测神器,未授权访问无所遁形
针对Spring站点未授权访问问题,现有工具难以检测如Swagger、Actuator等组件漏洞,且缺乏修复建议。全新AI工具基于Aipy开发,具备图形界面,支持一键扫描常见Spring组件,自动识别未授权访问风险,按漏洞类型标注并提供修复方案,扫描结果可视化展示,支持导出报告,大幅提升渗透测试与漏洞定位效率。
|
11月前
|
缓存 Java API
Spring WebFlux 2025 实操指南详解高性能非阻塞 API 开发全流程核心技巧
本指南基于Spring WebFlux 2025最新技术栈,详解如何构建高性能非阻塞API。涵盖环境搭建、响应式数据访问、注解与函数式两种API开发模式、响应式客户端使用、测试方法及性能优化技巧,助你掌握Spring WebFlux全流程开发核心实践。
1655 0
|
11月前
|
存储 NoSQL Java
探索Spring Boot的函数式Web应用开发
通过这种方式,开发者能以声明式和函数式的编程习惯,构建高效、易测试、并发友好的Web应用,同时也能以较小的学习曲线迅速上手,因为这些概念与Spring Framework其他部分保持一致性。在设计和编码过程中,保持代码的简洁性和高内聚性,有助于维持项目的可管理性,也便于其他开发者阅读和理解。
285 0
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
1433 0