🔍 一、Spring 缓存的核心思想
Spring 提供了一个声明式缓存抽象层(declarative caching abstraction),它的核心是:
通过注解(如
@Cacheable
)将方法的返回值缓存起来,避免重复执行昂贵的操作。
示例代码解释:
java
@Component
public class MathService {
@Cacheable("piDecimals")
public int computePiDecimal(int i) {
// 模拟耗时计算
return expensiveComputation(i);
}
}
@Cacheable("piDecimals")
表示这个方法的结果可以被缓存。- 第一次调用
computePiDecimal(5)
时,会执行方法,并把结果存入名为"piDecimals"
的缓存中。 - 下次再调用
computePiDecimal(5)
时,Spring 会先查缓存:- 如果命中 → 直接返回缓存值,不执行方法体。
- 如果未命中 → 执行方法并更新缓存。
✅ 好处:提升性能,避免重复计算或数据库查询。
🧱 二、缓存是如何工作的?------Cache 和 CacheManager
Spring 的缓存机制基于两个核心接口:
org.springframework.cache.Cache
:代表一个具体的缓存容器(比如一个叫"users"
的缓存)。org.springframework.cache.CacheManager
:管理多个Cache
实例,负责创建和获取缓存。
Spring 本身不提供缓存实现,它只是一个抽象层,你可以接入各种实际的缓存技术(如 Redis、Caffeine、EhCache 等)。
⚙️ 三、Spring Boot 如何自动配置缓存?
当你在项目中使用了 @EnableCaching
注解后,Spring Boot 会尝试自动配置一个 CacheManager
。
自动检测顺序(优先级从高到低):
- Generic -- 如果你自己定义了
Cache
Bean - JCache (JSR-107) -- 如 EhCache 3, Hazelcast, Infinispan
- EhCache 2.x
- Hazelcast
- Infinispan
- Couchbase
- Redis
- Caffeine
- Simple -- 使用
ConcurrentHashMap
的内存缓存(默认兜底)
📌 注意 :只要你的 classpath 下有对应的依赖(比如引入了 spring-boot-starter-data-redis
),Spring Boot 就会自动选择相应的缓存实现。
📦 四、如何启用缓存功能?
步骤 1:添加依赖
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
这个 starter 会引入 spring-context-support
,支持 JCache、EhCache、Caffeine 等。
步骤 2:开启缓存支持
在配置类上加上:
java
@EnableCaching
@SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
🛠️ 五、常见缓存提供者简要说明
缓存类型 | 特点 |
---|---|
Simple | 默认实现,用 ConcurrentHashMap 存数据,仅适用于开发/测试环境,重启即丢失。 |
Caffeine | Java 8 高性能本地缓存,推荐用于本地缓存场景(替代 Guava Cache)。 |
Redis | 分布式缓存,适合多实例部署、需要共享缓存的场景。 |
EhCache / Infinispan / Hazelcast | 企业级本地或分布式缓存解决方案。 |
JCache (JSR-107) | 标准化缓存 API,可跨厂商切换(如从 EhCache 换成 Infinispan)。 |
❓ 六、"spring.cache.type=none
" 是什么意思?
这是你问题的关键点。
配置示例:
properties
spring.cache.type=none
✅ 含义解释:
强制 Spring Boot 禁用缓存自动配置 ,使用一个"空操作"(no-op)的
CacheManager
。
也就是说:
- 即使你加了
@EnableCaching
和@Cacheable
注解, - 方法仍然会被正常执行多次,
- 缓存逻辑完全不起作用,也不会报错。
🎯 使用场景:
主要用于:
- 测试环境:你想确保所有方法都真实执行,避免缓存影响测试结果。
- 某些 Profile 下关闭缓存 :比如在
dev
环境开启缓存,在test
环境关闭。
yaml
# application-test.yml
spring:
cache:
type: none
这样在运行单元测试时,就不会因为缓存导致数据不一致或测试失败。
⚠️ 注意事项:
- 如果你不设置
spring.cache.type=none
,但又没有任何缓存库(如 Redis、Caffeine),Spring Boot 会默认使用 Simple 缓存(基于ConcurrentMap
)。 - 所以如果你想彻底关闭缓存行为 ,就必须显式设置为
none
。
✅ 七、总结:如何理解 spring.cache.type=none
问题 | 回答 |
---|---|
spring.cache.type=none 是干什么的? |
显式禁用缓存功能,使用 no-op 的 CacheManager |
它和"没有缓存依赖"有什么区别? | 没有依赖时会启用 Simple 缓存;而 none 是彻底关闭 |
什么时候用? | 测试环境、调试、不想让缓存干扰逻辑时 |
会影响 @Cacheable 注解吗? |
会!注解仍然存在,但不会生效,方法每次都执行 |
是否需要 @EnableCaching ? |
需要。但即使启用了,type=none 也会让缓存无效 |
💡 补充建议
- 开发阶段可以用
Simple
或Caffeine
做本地缓存。 - 生产环境建议使用
Redis
或Caffeine + Redis
结合(本地+分布式)。 - 不要混合使用 Spring Cache 注解(如
@Cacheable
)和 JSR-107 注解(如@CacheResult
)。 - 使用
CacheManagerCustomizer
可以精细控制缓存行为(如是否允许 null 值、TTL 等)。
📚 参考资料
如果你还有具体的问题,比如:
- 如何配置 Redis 缓存?
- 如何清除缓存(
@CacheEvict
)? - 如何更新缓存(
@CachePut
)? - 多个缓存如何管理?
欢迎继续提问!