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;
    }
​
}
复制代码
相关推荐
dgiij9 分钟前
node.js的进程保活
后端·node.js·bash
蒜蓉大猩猩14 分钟前
Node.js - Express框架
后端·架构·node.js·express
蒜蓉大猩猩43 分钟前
Node.js --- 详解MongoDB与Mongoose
数据库·后端·mongodb·node.js
昔我往昔1 小时前
Spring Boot中如何处理跨域请求(CORS)
java·spring boot·后端
昔我往昔1 小时前
Spring Boot中的配置文件有哪些类型
java·spring boot·后端
Zhu_S W1 小时前
SpringBoot 自动装配原理及源码解析
java·spring boot·spring
西岸风1661 小时前
【全套】基于Springboot的房屋租赁网站的设计与实现
java·spring boot·后端
ben19872 小时前
二、使用Spring Boot构建AI应用程序
后端
ben19873 小时前
三、ChatClient&Chat Model简化与AI模型的交互
后端
hlvy3 小时前
如何使用策略模式并让spring管理
java·开发语言·后端·spring·策略模式