开发者

使用Spring Cache本地缓存示例代码

开发者 https://www.devze.com 2025-08-19 10:32 出处:网络 作者: 会飞的架狗师
目录一、Spring Cache简介核心特点:二、基础配置1. 添加依赖2. 启用缓存3. 缓存配置方案方案1:通过 yml 配置文件方案2:自定义 Bean三、 缓存注解使用示例1.@Cacheable - 数据查询缓存2.@CachePut - 更新数据并缓存
目录
  • 一、Spring Cache简介
    • 核心特点:
  • 二、基础配置
    • 1. 添加依赖
    • 2. 启用缓存
    • 3. 缓存配置方案
      • 方案1:通过 yml 配置文件
      • 方案2:自定义 Bean
  • 三、 缓存注解使用示例
    • 1.@Cacheable - 数据查询缓存
      • 2.@CachePut - 更新数据并缓存
        • 3.@CacheEvict - 删除缓存
          • 4. @Caching - 组合操作
            • 5. 条件缓存 (condition/unless)
              • 6. 异步缓存加载
              • 四、特殊场景处理
                • 1. 缓存空值防御
                  • 2. 复合缓存键
                  • 五、经验之谈
                    • 总结 

                      一、Spring Cache简介

                      Spring Cache 是 Spring 框架提供的一套声明式缓存抽象层,通过注解方式简化缓存操作,它通过在方法上添加注解(如 @Cacheable、@CacheEvict)来地管理缓存操作,无需手动编写缓存逻辑。

                      它支持多种缓存实现(如 Caffeine、Redis、EhCache),并统一了缓存访问的 API。

                      这里需要注意两点:

                      1. Spring Cache 只是一个声明式的抽象缓存层,意思是它只提供了接口,不提供实现
                      2. 具体的实现可以有很多,比如 Caffeine,Redis,EhCache 这些,只要实现了这些接口,就可以被 Spring Cache 使用。

                      核心特点:

                      • 基于注解的声明式缓存
                      • 支持 SpEL 表达式
                      • 自动与 Spring 生态集成
                      • 支持条件缓存

                      二、基础配置

                      1. 添加依赖

                      <!-- Spring Boot Cache Starter -->
                      <dependency>
                          <groupId>org.springframework.boot</groupId>
                          <artifactId>spring-boot-starter-cache</artifactId>
                      </dependency>
                      
                      <!-- 如果使用Redis -->
                      <dependency>
                          <groupId>org.springframework.boot</groupId>
                          <artifactId>spring-boot-starter-data-redis</artifactId>
                      </dependency>
                      
                      <!-- 如果使用caffeine -->
                      <dependency>
                          <groupId>com.github.ben-manes.caffeine</groupId>
                          <artifactId>caffeine</artifactId>
                      </dependency>
                      

                      2. 启用缓存

                      在启动类添加@EnableCaching注解:

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

                      3. 缓存配置方案

                      方案1:通过 yml 配置文件

                      spring:
                        cache:
                          type: caffeine
                          caffeine:
                            spec: maximumSize=500,expireAfterWrite=60s
                          # 或者分开配置
                          cache-names: users,products
                          caffeine.spec: # 全局默认配置
                            maximumSize=1000,
                            expireAfterAccess=30m
                      

                      方案2:自定义 Bean

                      @Configuration  // 标记这是一个Spring配置类
                      public class CacheConfig 编程客栈{
                      
                          /**
                           * 创建并配置Caffeine缓存管理器
                           *
                           * @return CacheManager 实例,用于管理www.devze.com应用中所有缓存
                           *
                           * 主要配置参数说明:
                           * - initialCapacity: 初始缓存空间大小(提升初始性能)
                           * - maximumSize: 缓存最大容量(基于条目数)
                           * - expireAfterWrite: 写入后过期时间(数据一致性优先场景)
                           * - recordStats: 开启统计功能(用于监控和调优)
                           */
                          @Bean
                          public CacheManager cacheManager() {
                              // 创建Caffeine缓存管理器实例
                              CaffeineCacheManager cacheManager = new CaffeineCacheManager();
                      
                              // 配置Caffeine缓存参数
                              cacheManager.setCaffeine(Caffeine.newBuilder()
                                      .initialCapacity(100)      // 初始容量100个条目
                                      .maximumSize(1000)          // 最大缓存1000个条目,超过后按LRU淘汰
                                      .expireAfterWrite(10, TimeUnit.MINUTES)  // 写入10分钟后过期
                                      .recordStats());           // 启用缓存统计(命中率等)
                      
                              return cacheManager;
                          }
                      
                          /**
                           * 创建短期缓存实例(独立于主缓存管理器)
                           *
                           * @return Cache 实例,适用于高频访问的临时数据
                           *
                           * 典型使用场景:
                           * - 高频访问的临时数据
                           * - 需要快速失效的验证码等
                           * - 与其他缓存不同生命周期的数据
                           */
                          @Bean(name = "shortTermCache")  // 指定Bean名称便于按名称注入
                          public Cache shortTermCache() {
                              return Caffeine.newBuilder()
                                      .expireAfterWrite(1, TimeUnit.MINUTES)  // 1分钟过期(短期存储)
                                      .maximumSize(100)                       // 最大100个条目
                                      .build();                               // 构建Cache实例
                          }
                      }
                      

                      三、 缓存注解使用示例

                      • @Cacheable:用于标记方法,表示该方法将结果缓存起来,下次调用时直接从缓存中获取结果,而不需要重新执行方法。
                      • @CacheEvict:用于标记方法,表示该方法将清除缓存,通常用于删除缓存。
                      • @CachePut:用于标记方法,表示该方法将更新缓存,通常用于更新缓存。
                      • @Caching:用于组合多个缓存注解,可以同时使用多个缓存注解。
                      • @CacheConfig:用于标记类,表示该类中的所有方法将使用指定的缓存配置。

                      1.@Cacheable - 数据查询缓存

                      /**
                       * 根据ID获取用户信息(带缓存)
                       * @param id 用户ID
                       * @return 用户对象,如果不存在返回null
                       * 
                       * @Cacheable 参数说明:
                       * - value/cacheNames: 指定缓存名称(对应Caffeine配置)
                       * - key: 缓存键,使用SpEL表达式(#参数名引用方法参数)
                       * - unless: javascript条件表达式,当结果满足条件时不缓存
                       */
                      @Cacheable(value = "users", key = "#id", unless = "#result == null")
                      public User getUserById(Long id) {
                          log.info("执行数据库查询,用户ID: {}", id);
                          return userRepository.findById(id).orElse(null);
                      }
                      

                      2.@CachePut - 更新数据并缓存

                      /**
                       * 更新用户信息(同时更新缓存)
                       * @param user 用户对象
                       * @return 更新后的用户对象
                       * 
                       * @CachePut 特点:
                       * - 总是执行方法体
                       * - 用返回值更新缓存
                       * - 适用于"先写后读"场景
                       */
                      @CachePut(value = "users", key = "#user.id")
                      public User updateUser(U编程客栈ser user) {
                          log.info("更新用户数据: {}", user.getId());
                          return userRepository.save(user);
                      }
                      

                      3.@CacheEvict - 删除缓存

                      /**
                       * 删除用户(同时移除缓存)
                       * @param id 用户ID
                       * 
                       * @CacheEvict 参数说明:
                       * - beforeInvocation: 是否在方法执行前清除缓存(默认false)
                       * - allEntries: 是否清空整个缓存区域(慎用)
                       */
                      @Cwww.devze.comacheEvict(value = "users", key = "#id")
                      public void deleteUser(Long id) {
                          log.info("删除用户: {}", id);
                          userRepository.deleteById(id);
                      }
                      

                      4. @Caching - 组合操作

                      组合操作允许在单个方法上同时使用多个缓存注解,以实现更复杂的缓存策略。

                      /**
                      * 更新用户状态(复杂缓存操作)
                      * @param userId 用户ID
                      * @param status 新状态
                      *
                      * 典型场景:
                      * - 更新用户缓存
                      * - 同时失效用户列表缓存
                          */
                          @Caching(
                          put = @CachePut(value = "users", key = "#userId"),
                          evict = @CacheEvict(value = "userList", allEntries = true)
                          )
                          public void updateUserStatus(Long userId, UserStatus status) {
                          log.info("更新用户{}状态为{}", userId, status);
                          userRepository.updateStatus(userId, status);
                          }
                      

                      5. 条件缓存 (condition/unless)

                      条件缓存允许在缓存注解中添加 SpEL 条件表达式,以控制缓存的触发时机。

                      /**
                       * 获取用户详情(带条件缓存)
                       * @param id 用户ID
                       * 
                       * 缓存条件说明:
                       * - condition: 只有id>1000时才走缓存
                       * - unless: 结果中status=DELETED时不缓存
                       */
                      @Cacheable(value = "users", 
                                 key = "#id",
                                 condition = "#id > 1000",
                                 unless = "#result != null && #result.status == T(com.example.UserStatus).DELETED")
                      public User getUserDetail(Long id) {
                          log.info("查询用户详情: {}", id);
                          return userRepository.findDetailById(id);
                      }
                      

                      6. 异步缓存加载

                      /**
                       * 获取用户订单列表(异步缓存)
                       * @param userId 用户ID
                       * 
                       * @sync = true 表示:
                       * - 多线程并发时,只有一个线程会执行加载
                       * - 其他线程等待结果
                       */
                      @Cacheable(value = "orders", key = "#userId", sync = true)
                      public List<Order> getUserOrders(Long userId) {
                          log.info("加载用户{}订单数据...", userId);
                          return orderService.getOrdersByUser(userId);
                      }
                      

                      四、特殊场景处理

                      1. 缓存空值防御

                      /**
                       * 查询用户(防穿透处理)
                       * @param name 用户名
                       * 
                       * 特殊处理:
                       * - 对null结果也进行缓存(特殊标记对象)
                       * - 设置较短过期时间(配置文件中定义)
                       */
                      @Cacheable(value = "usersByName", 
                                 key = "#name",
                                 unless = "#result == null || #result == T(com.example.CacheConstants).NULL_OBJECT")
                      public User getUserByName(String name) {
                          User user = userRepository.findByName(name);
                          return user != null ? user : CacheConstants.NULL_OBJECT;
                      }
                      

                      2. 复合缓存键

                      /**
                       * 获取用户在某系统的权限列表
                       * @param userId 用户ID 
                       * @param systemCode 系统编码(如:"OA", "CRM"等)
                       * @return 权限字符串集合
                       * 
                       * 缓存Key设计说明:
                       * 1. 使用复合Key结构:`用户ID_系统编码`(如:123_OA)
                       * 2. 优点:
                       *    - 避免不同系统权限缓存冲突
                       *    - 支持按用户+系统维度独立管理缓存
                       * 3. 缓存条件:仅当结果非空时缓存
                       */
                      @Cacheable(value = "userPermissions", 
                                 key = "#userId + '_' + #systemCode",
                                 unless = "#result == null || #result.isEmpty()")
                      public Set<String> getUserSystemPermissions(Long userId, String systemCode) {
                          log.debug("查询用户[{}]在系统[{}]的权限", userId, systemCode);
                          return permissionService.findPermissions(userId, systemCode);
                      }
                      
                      /**
                       * 获取用户角色列表(带枚举参数的Key示例)
                       * @param userId 用户ID
                       * @param roleType 角色类型枚举
                       * 
                       * 枚举类型处理技巧:
                       * 1. 调用枚举的name()方法转换为字符串
                       * 2. 最终Key格式:`userId:roleType`(如:123:ADMIN)
                       */
                      @Cacheable(value = "userRoles", 
                                 key = "#userId + ':' + #roleType.name()")
                      public List<Role> getUserRoles(Long userId, RoleType roleType) {
                          return roleService.findByUserAndType(userId, roleType);
                      }
                      

                      五、经验之谈

                      • 推荐为每个 @Cacheable 方法添加 unless 条件防御 null
                      • 业务更新方法建议同时使用 @CachePut@CacheEvict
                      • 高频访问数据考虑设置 sync=true

                      总结 

                      到此这篇关于使用Spring Cache本地缓存的文章就介绍到这了,更多相关Spring Cache本地缓存内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

                      0

                      精彩评论

                      暂无评论...
                      验证码 换一张
                      取 消

                      关注公众号