缓存模块
缓存存在于工作的方方面面,小到 CPU 级别,大到项目级别,都会用到缓存。当然了,这也是面试的一个高频的重点区域
从原理入手,带大家从概念上以及现有的设计规范上认识缓存的设计理念
从实践出发,站在Spring的肩膀上去编排我们自己的缓存模块
根据缓存框架,将常用的缓存方案插件式的集成到项目中来
JSR 107
JSR107(Java Specification Requests ) 规范。就是关于如何使用缓存的规范,是 java 提供的一个接口规范,类似于 JDBC 规范,没有具体的实现,具体的实现就是 ehcache 等这些缓存解决方案
JSR107 核心接口
Java Caching USR-107) 定义了5个核心接口,分别是CachingProvider、CacheManager、Cache、Entry和Expiry.
- CachingProvider(缓存提供者):创建、配置、获取、管理和控制多个 CacheManager。
- CacheManager(緩存管理器):创建、配置、获取、管理和控制多个唯一命名的Cache,Cache存在于CacheManager的上下文中。一个 CacheManager 仅对应一个 CachingProvider
- Cache(缓存):是由 CacheManager 管理的,CacheManager 管理 Cache 的生命周期,Cache 存在于 CacheManager 的上下文中,是一个类似 map 的数据结构,并临时存储以 key 为索引的值。一个 Cache 仅被一个 CacheManager 所拥有
- Entry(缓存键值对):是一个存储在 Cache 中的 key-value 对
- Expiry(缓存时效):每一个存储在 Cache 中的条目都有一个定义的有效期。一旦超过这个时间,条目就自动过期,过期后,条目将不可以访问、更新和删除操作。缓存有效期可以通过 ExpiryPolicy 设置
使用 jsr-107需导入的依赖:
xml
<dependency>
<groupid>javax.cache</groupid>
<artifactid>cache-api</artifactid>
</dependency>Spring 对 Cache 的抽象架构
Spring 对缓存的抽象主要包括以下几个核心接口和类:
CacheManager: 这是 Spring 缓存管理器的核心接口,它负责管理多个Cache实例。每个Cache实例都代表一个缓存区域Cache: 这是 Spring 缓存区域的核心接口,它定义了缓存的基本操作,如查找、更新、插入和删除@Cacheable: 这是一个方法级别的注解,用于指示 Spring 在调用方法之前,首先从缓存中查找方法的结果。如果找到了结果,就返回缓存的值,否则调用方法,然后将结果放入缓存中@CachePut: 这是一个方法级别的注解,用于指示 Spring 在方法调用后,无论方法的结果如何,都将其放入缓存中@CacheEvict: 这是一个方法级别的注解,用于指示 Spring 在方法调用后,从缓存中删除指定的数据@Caching: 这是一个方法级别的注解,用于组合多个缓存注解@CacheConfig: 这是一个类级别的注解,用于共享一些常见的缓存设置
这些抽象结构使得 Spring 的缓存非常灵活,可以适应各种不同的缓存需求。同时,由于这些抽象结构都是接口或注解,因此可以很容易地扩展和定制
Spring 对于 Cache 的抽象架构
创建 cache 模块
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.xiaoye</groupId>
<artifactId>framework</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>cache</artifactId>
<packaging>pom</packaging>
<modules>
<module>cache-core</module>
<module>cache-caffeine</module>
<module>cache-redis</module>
</modules>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>cache-caffeine 模块
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.xiaoye</groupId>
<artifactId>cache</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>cache-caffeine</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.xiaoye</groupId>
<artifactId>cache-core</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
</dependencies>
</project>
framework/cache/cache-caffeine/src/main/java/com/xiaoye/cache/caffeine/config/CaffeineCacheProperties.java
package com.xiaoye.cache.caffeine.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* Caffeine Cache自定义配置属性类
*/
@Data
@Component
@ConfigurationProperties(prefix = "com.xiaoye.cache.caffeine")
public class CaffeineCacheProperties {
/**
* 缓存初始容量
* com.xiaoye.cache.caffeine.init-cache-capacity
*/
private Integer initCacheCapacity = 256;
/**
* 缓存最大容量,超过之后会按照 recently or very often(最近最少)策略进行缓存剔除
* com.xiaoye.cache.caffeine.max-cache-capacity
*/
private Long maxCacheCapacity = 10000L;
/**
* 是否允许空值 null 作为缓存的 value
* com.xiaoye.cache.caffeine.allow-null-value
*/
private Boolean allowNullValue = Boolean.TRUE;
}
framework/cache/cache-caffeine/src/main/java/com/xiaoye/cache/caffeine/config/CaffeineCacheConfig.java
package com.xiaoye.cache.caffeine.config;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.xiaoye.cache.core.constants.CacheConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
@SpringBootConfiguration
@EnableCaching // 开启缓存
@Slf4j
public class CaffeineCacheConfig {
@Autowired
private CaffeineCacheProperties properties;
@Bean
public CacheManager caffeineCacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager(CacheConstants.Y_PAN_CACHE_NAME);
cacheManager.setAllowNullValues(properties.getAllowNullValue());
Caffeine<Object, Object> caffeineBuilder = Caffeine.newBuilder()
.initialCapacity(properties.getInitCacheCapacity())
.maximumSize(properties.getMaxCacheCapacity());
cacheManager.setCaffeine(caffeineBuilder);
log.info("the caffeine cache manager is loaded successfully!");
return cacheManager;
}
}配置提示 framework/cache/cache-caffeine/src/main/resources/META-INF/additional-spring-configuration-metadata.json
json
{
"properties": [
{
"name": "com.xiaoye.cache.caffeine.init-cache-capacity",
"type": "java.lang.Integer",
"description": "Caffeine 缓存的初始容量",
"defaultValue": 256
},
{
"name": "com.xiaoye.cache.caffeine.max-cache-capacity",
"type": "java.lang.Long",
"description": "Caffeine 缓存的最大容量",
"defaultValue": "10000L"
},
{
"name": "com.xiaoye.cache.caffeine.allow-null-value",
"type": "java.lang.Boolean",
"description": "Caffeine 缓存是否允许 null 作为 value 的属性",
"defaultValue": "true"
}
]
}cache-redis 模块
版本差异(缓存模块 → 当前)
| 特性 | 旧版 | 当前 |
|---|---|---|
| 本地缓存 | Caffeine | 不变;Caffeine 3.x 支持 JDK 17/21 |
| 分布式缓存 | Redis 6.2.6 | Redis 7.x;客户端 Lettuce 6.x(spring-data-redis 3.x) |
| 多级缓存 | Caffeine + Redis | 不变;注意缓存一致性(先更新 DB 再删缓存) |
| 缓存注解 | @Cacheable 等 | 不变;Boot 3.x 中 spring.cache.type 配置键稳定 |
缓存分层设计与一致性策略(Cache Aside 模式)不随版本变化;升级重点是 Redis 7.x 与 spring-data-redis 3.x 的兼容。