Spring Cache

Spring Cache缓存框架


‌**Spring Cache** ‌是Spring框架提供的一种缓存抽象机制,用于简化应用中的缓存操作。它通过将方法的返回值缓存起来,当下次调用同一方法时,如果传入的参数与之前的调用相同,就可以直接从缓存中获取结果,而不需要再执行方法体中的代码,从而提高系统的性能和响应速度‌。

Spring Cache的特点

  1. 声明式缓存 ‌:通过在方法上添加注解,如 @Cacheable@CachePut@CacheEvict等来声明缓存的行为,无需手动编写缓存代码‌。

  2. 多种缓存支持 ‌:Spring Cache提供了对多种缓存框架的支持,包括Redis、Ehcache、Guava Cache、Caffeine等,可以根据需要选择合适的缓存实现‌。

  3. 缓存策略配置 ‌:可以通过配置文件或者编程方式来配置缓存的策略,包括缓存的过期时间、缓存的淘汰策略等‌。

  4. 注解灵活应用‌:通过在方法上添加不同的注解,可以实现缓存的读取、更新和清除等操作,根据业务需求进行灵活配置‌。

  5. 缓存切面自动代理‌:Spring Cache通过AOP技术,利用代理模式在方法执行前后拦截,自动处理缓存相关的操作,对业务代码无侵入‌。

Spring Cache的核心概念和原理

Spring Cache利用AOP(面向切面编程)实现了基于注解的缓存功能。它通过在方法上添加注解来声明缓存行为,Spring Cache会在方法执行前后进行拦截,检查缓存中是否有对应的数据。如果有,则直接返回缓存结果;如果没有,则执行方法并将结果存入缓存‌。

Spring Cache的使用方法

Spring Cache提供了注解式和编程式两种使用方式:

  • 注解式 ‌:通过在方法上添加@Cacheable@CacheEvict等注解来声明缓存行为。例如,@Cacheable(value = "users", key = "#id")表示将方法的返回值缓存到名为"users"的缓存中,缓存的key为方法的参数id。

  • 编程式 ‌:通过编程方式使用CacheManager接口来操作缓存。例如,获取或设置缓存的值等操作‌

常用注解

注解
@EnableCaching 开启缓存功能,通常加在启动类上
@Cacheable 在方法执行之前先查询缓存中是否有数据,如果有数据,则直接返回缓存数据;如果没有缓存数据,调用方法并将方法的返回值放到缓存中
@Cacheput 将方法的返回值放到缓存中
@CacheEvict 将一条或多条数据从缓存中删除

详解

@EnableCaching

@EnableCaching 是 Spring Framework 中用于启用缓存支持的一个注解。当您在 Spring Boot 应用程序的主类或其他配置类上使用此注解时,Spring 会自动检测并配置缓存相关的 Bean,以便您可以在应用程序中使用缓存功能。

作用

  • 启用缓存抽象@EnableCaching 注解告诉 Spring 容器启用缓存抽象,这包括解析缓存注解(如 @Cacheable@CachePut@CacheEvict 等)以及注册必要的缓存基础设施 Bean(如 CacheManager)。

  • 自动配置 :在 Spring Boot 应用程序中,@EnableCaching 注解通常与自动配置一起使用,以简化缓存的配置过程。Spring Boot 会自动检测添加的缓存依赖(如 Caffeine、EhCache、Redis 等),并配置相应的 CacheManager。

@Cacheable

用于标记那些其返回值是可以被缓存的方法。当带有 @Cacheable 注解的方法被调用时,Spring Cache 会先检查指定的缓存中是否已经存在该方法的返回值。如果存在,则直接返回缓存中的值,避免重复计算;如果不存在,则调用该方法,将返回值缓存起来,并返回该值。

属性详解

  • valuecacheNames:指定缓存的名称。可以使用数组或逗号分隔的字符串来指定多个缓存。

  • key:指定缓存的键。默认为方法参数。可以使用 SpEL(Spring Expression Language)表达式来动态生成键。

  • condition:指定一个条件表达式,用于决定缓存是否生效。如果表达式的结果为 false,则不缓存方法的返回值。

  • unless:指定一个条件表达式,用于在方法执行后决定是否缓存返回值。如果表达式的结果为 true,则不缓存方法的返回值。

@Cacheput

用于更新缓存中的值。与 @Cacheable 注解不同,@CachePut 注解的方法每次都会被调用,并将返回值放入指定的缓存中。这通常用于那些每次调用都需要更新缓存的场景。

属性详解(属性与 @Cacheable相似**)**

  • valuecacheNames:指定缓存的名称。可以使用数组或逗号分隔的字符串来指定多个缓存。

  • key:指定缓存的键。默认为方法参数。可以使用 SpEL(Spring Expression Language)表达式来动态生成键。

  • condition:指定一个条件表达式,用于决定缓存是否生效。如果表达式的结果为 false,则不更新缓存。

@CacheEvict

用于从缓存中移除数据。它通常用于在数据发生变化时(如数据被删除或更新)确保缓存的一致性。

注解详解

  • valuecacheNames:指定要移除数据的缓存名称。可以使用数组或逗号分隔的字符串来指定多个缓存。

  • key:指定要移除数据的缓存键。默认为方法参数。可以使用 SpEL(Spring Expression Language)表达式来动态生成键。

  • allEntries:指定是否移除缓存中的所有数据。如果设置为 true,则忽略 key 属性,移除指定缓存中的所有条目。

  • beforeInvocation:指定是否在方法执行前移除缓存数据。默认为 false,即在方法执行后移除。如果设置为 true,则在方法执行前移除缓存数据,这可以确保在方法执行过程中不会访问到旧的缓存数据。

  • condition:指定一个条件表达式,用于决定缓存移除是否生效。如果表达式的结果为 false,则不移除缓存数据。

Spring 的表达式语言

‌**Spring Cache中的SpEL表达式(Spring Expression Language)用于动态生成缓存键、条件判断和排除策略等**

常见用法
  • 属性访问 :使用 . 运算符访问对象的属性,如 person.name

  • 方法调用 :使用 () 运算符调用对象的方法,如 person.getName()。如果方法没有参数,括号可以省略,如 person.isAdult

  • 在SpEL表达式中,可以使用 # 符号引用变量,如 #myVar

SpEL表达式可以基于上下文环境,使用缓存抽象提供与root对象相关的内置参数下面给出例子:

  • #root.methodName:当前被调用的方法名。

  • #root.target:当前被调用的目标对象实例。

  • #root.args:当前被调用的方法参数列表。

  • #result:方法执行后的返回值‌

项目中整合SpringCache框架

①改pom文件,导入相关的依赖

我演示的是使用Redis作为缓存数据库,所以一并导入整合Redis的技术依赖,你可以跟据你所使用的缓存数据库进行给更改和配置

XML 复制代码
 <!--spring整合cache的场景依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

②写yml文件,声明相关配置信息

在yml配置文件中声明好数据库的相关配置,如登录所需要的用户名,密码等...

XML 复制代码
#端口
server:
  port: 8888
 
#数据库配置
spring:
  redis:
    host: 192.168.230.100     # Redis服务器地址
    database: 0         # Redis数据库索引(默认为0)
    port: 6379          # Redis服务器连接端口
#    password: ld123456  # Redis服务器连接密码(默认为空)
  datasource:
    url: jdbc:mysql://192.168.230.100:3306/tmp_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
    username: root
    password: 1234
    driver-class-name: com.mysql.jdbc.Driver
 
#打印日志
logging:
  level:
    com.donleo.cache.mapper: debug
mybatis:
  mapper-locations: classpath:mappers/*.xml
  type-aliases-package: com.itheima.cache.model
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

③在配置类中进行Redis缓存的相关配置

java 复制代码
@Configuration
@EnableCaching
public class CacheConfig {

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofHours(1)) // 设置缓存条目的过期时间
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));

        return RedisCacheManager.builder(redisConnectionFactory)
                .cacheDefaults(redisCacheConfiguration)
                .build();
    }

    @Bean
    public KeyGenerator keyGenerator() {
        return (target, method, params) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getSimpleName());
            sb.append(".");
            sb.append(method.getName());
            sb.append("[");
            for (Object obj : params) {
                sb.append(obj.toString());
            }
            sb.append("]");
            return sb.toString();
        };
    }


//=======================================================================================
上面是缓存管理器,key生成器的相关配置,如果需要可以自行修改,进行更加细致化的配置,获得更加好的使用体验。
//=======================================================================================

    @Bean//配置缓存的模板对象
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        log.info("开始创建Redis的模板对象....................")
        //开始创建Redis的模板对象
        RedisTemplate template = new RedisTemplate();
        
        //设置Redis的工厂连接对象
        template.setConnectionFactory(redisConnectionFactory);

        //设置redis key的序列化器
        template.setKeySerializer(new StringRedisSerializer());

        //设置redis value的序列化器
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        return template;
    }
}

④在业务类中使用缓存框架注解进行缓存的使用

java 复制代码
@RestController
@RequestMapping("/user")
@Slf4j
@EnableCaching
public class UserController {
​
    @Autowired
    private UserMapper userMapper;
​
    @PostMapping
    @CachePut(cacheNames = "userCache" ,key = "#user.id")//对象导航
    //如果使用spring cache缓存数据 key的生成为cacheName::key
    //插入数据的同时存入缓存
    public User save(@RequestBody User user){
        userMapper.insert(user);
        return user;
    }
​
    @DeleteMapping
    @CacheEvict(cacheNames = "userCache",key = "#id")
    //删除指定的键值对数据
    public void deleteById(Long id){
        userMapper.deleteById(id);
    }
​
    @DeleteMapping("/delAll")
    @CacheEvict(cacheNames = "userCache",allEntries = true)
    //删除所有的键值对数据
    public void deleteAll(){
        userMapper.deleteAll();
    }
​
    @GetMapping
    //判断缓存中是否存在数据,没有就查询数据库
    @Cacheable(cacheNames = "userName",key = "#id")
    public User getById(Long id){
        User user = userMapper.getById(id);
        return user;
    }
​
}
复制代码
相关推荐
全栈派森1 小时前
云存储最佳实践
后端·python·程序人生·flask
CircleMouse1 小时前
基于 RedisTemplate 的分页缓存设计
java·开发语言·后端·spring·缓存
獨枭2 小时前
使用 163 邮箱实现 Spring Boot 邮箱验证码登录
java·spring boot·后端
维基框架2 小时前
Spring Boot 封装 MinIO 工具
java·spring boot·后端
秋野酱2 小时前
基于javaweb的SpringBoot酒店管理系统设计与实现(源码+文档+部署讲解)
java·spring boot·后端
☞无能盖世♛逞何英雄☜2 小时前
Flask框架搭建
后端·python·flask
进击的雷神3 小时前
Perl语言深度考查:从文本处理到正则表达式的全面掌握
开发语言·后端·scala
进击的雷神3 小时前
Perl测试起步:从零到精通的完整指南
开发语言·后端·scala
努力学习的明3 小时前
Spring MVC 对 JavaWeb 的优化:从核心组件到注解
java·spring·mvc·web
豌豆花下猫4 小时前
Python 潮流周刊#102:微软裁员 Faster CPython 团队(摘要)
后端·python·ai