Spring Boot Cache 解刨:@Cacheable 注解用法 + Redis 缓存优化,从架构设计到批量缓存性能提升指南
2026-07-06 15:22:00
Honesty Blog 首页 文章 友链 关于我 瞬间 开往 归档 标签Spring Boot Cache 解刨:@Cacheable 注解用法 + Redis 缓存优化,从架构设计到批量缓存性能提升指南 发布于: 2025-8-22 最后更新: 2025-8-22 次查看字数 9615阅读时长≈ 25 分钟技术分享 Spring Redis Cache 全屏阅读 typePoststatusPublisheddateAug 22, 2025 12:34slugspring-boot-cache-cacheable-redis-optimization-guidesummary详解 Spring Boot Cache 核心技术,包括 @Cacheable 配置、CacheManager 使用、Redis 缓存选型与二级缓存实战,教你批量缓存优化技巧,轻松提升应用性能。Covering Spring Boot Cache essentials: @Cacheable setup, CacheManager, Redis selection, two-level & batch caching to boost app performance effectively.tagsSpringRedisCachecategory技术分享iconpasswordmusicIdcatalogarchivessort缓存是提升应用性能的"利器",尤其是在数据查询频繁、数据库压力大的场景中,用好缓存能让应用响应速度提升数倍甚至数十倍。Spring Boot提供的Cache模块,通过优雅的抽象和注解驱动,让开发者无需深入了解各种缓存技术的细节,就能轻松实现缓存功能。今天我们就从基础概念到实战技巧,全面剖析Spring Boot Cache模块的核心原理和使用方法,尤其会深入探讨其设计模式和架构思想背后的深层逻辑。一、Spring Boot Cache核心概念:缓存抽象的魅力提到缓存,你可能会想到Redis、EhCache、Caffeine等具体的缓存技术。这些技术各有特点,但对于开发者来说,直接使用它们会面临一个问题:换一种缓存技术,代码可能就要大改。Spring Boot Cache的核心思想就是**"缓存抽象"**——通过定义统一的接口,屏蔽不同缓存技术的差异,让开发者专注于业务逻辑,而不是具体的缓存实现。1.1 核心接口:缓存世界的"规则制定者"Spring Boot Cache定义了一系列核心接口,这些接口就像缓存世界的"规则",无论底层用哪种缓存技术,都要遵守这些规则。理解这些接口,是掌握Spring Boot Cache的关键。接口名称核心作用通俗理解Cache定义了缓存的基本操作(get、put、evict等)单个缓存实例,相当于一个"缓存容器"CacheManager负责创建和管理Cache实例缓存的"大管家",管理所有缓存容器CacheResolver根据缓存操作的元数据,决定使用哪个Cache实例缓存的"导航仪",决定用哪个缓存容器KeyGenerator生成缓存的键(Key)缓存键的"生成器",给数据生成唯一标识CacheOperation封装@Cacheable等注解的元数据(如缓存名称、key规则等)缓存操作的"说明书",记录要执行的缓存动作CacheInterceptor通过AOP拦截方法,执行缓存逻辑(查缓存、更缓存等)缓存的"执行者",负责按说明书执行缓存操作这些接口的关系可以用一张架构图来表示:简单来说,整个流程是这样的:当我们调用一个加了缓存注解的方法时,CacheInterceptor会先拦截这个方法,通过CacheOperation获取注解里的配置信息,再用KeyGenerator生成缓存Key,然后让CacheResolver找CacheManager要合适的Cache实例,最后通过Cache实例操作底层的具体缓存(比如Redis)。1.2 注解驱动:一行注解搞定缓存逻辑Spring Boot Cache最方便的地方就是注解驱动——只需在方法上添加注解,就能自动实现缓存逻辑,无需手动写"查缓存-没命中查数据库-存缓存"的模板代码。常用的缓存注解有这些:注解名称核心作用使用场景@Cacheable方法执行前查缓存,命中则返回缓存值;未命中则执行方法,再把结果存缓存查询操作(如根据ID查用户)@CachePut方法执行后,将结果存入缓存(不影响方法本身执行)更新操作(如更新用户信息后同步更新缓存)@CacheEvict清除缓存中的指定数据删除操作(如删除用户后清除对应缓存)@Caching组合多个缓存操作(比如既查缓存又清缓存)复杂操作(如查询后需要清除关联缓存)@CacheConfig类级别配置缓存属性(如默认缓存名称、Key生成器)统一配置类中所有方法的缓存属性举个例子,用这些注解实现用户服务的缓存逻辑,代码会非常简洁:只需几行注解,就完成了缓存的查询、更新、清除逻辑,是不是很简单?这就是Spring Boot Cache的魅力所在。二、Spring Boot Cache的启动与配置:从"开关"到"定制"要使用Spring Boot Cache,首先得开启它的功能,然后根据需求配置缓存管理器。这部分我们就来看看Spring Boot Cache是如何启动的,以及如何配置不同的缓存实现。2.1 @EnableCaching:缓存功能的"总开关"使用Spring Boot Cache的第一步,是在配置类上添加@EnableCaching注解——这就像按下了缓存功能的"启动按钮"。这个注解的作用是告诉Spring:"我要启用缓存功能了,麻烦帮我加载相关的配置"。2.1.1 @EnableCaching的底层逻辑@EnableCaching的核心是通过@Import注解导入了一个叫CachingConfigurationSelector的类。这个类的作用是根据配置,选择加载不同的缓存配置类。我们来看简化后的源码:CachingConfigurationSelector会根据mode属性(默认是PROXY)选择导入对应的配置类。如果是PROXY模式,就导入ProxyCachingConfiguration——这个类是Spring Cache代理模式的核心配置类,里面定义了缓存功能所需的各种核心Bean。2.2 ProxyCachingConfiguration:缓存的"核心配置中心"ProxyCachingConfiguration是一个用@Configuration注解标记的配置类,它的作用是创建缓存功能的核心组件(比如缓存拦截器、缓存增强器等)。我们可以把它理解为缓存的"核心配置中心"。2.2.1 核心Bean的创建过程ProxyCachingConfiguration会创建三个关键Bean,它们共同支撑起缓存的运行:这三个Bean的关系可以用流程图表示:简单来说,cacheOperationSource负责"读注解"(解析@Cacheable等注解的配置),cacheInterceptor负责"执行逻辑"(按注解配置操作缓存),cacheAdvisor负责"织入AOP"(让拦截器能拦截到目标方法)。2.3 缓存配置规则:定制你的缓存行为Spring Boot Cache支持通过配置文件(如application.properties或application.yml)来定制缓存行为。常用的配置项有这些:配置项作用示例spring.cache.type指定缓存类型(如redis、ehcache、caffeine等)spring.cache.type=redisspring.cache.cache-names预定义缓存名称(启动时就创建这些缓存)spring.cache.cache-names=users,ordersspring.cache.redis.time-to-liveRedis缓存默认过期时间spring.cache.redis.time-to-live=30m(30分钟)spring.cache.redis.key-prefixRedis缓存Key的前缀spring.cache.redis.key-prefix=app1:spring.cache.redis.cache-null-values是否缓存null值(防止缓存穿透)spring.cache.redis.cache-null-values=truespring.cache.caffeine.specCaffeine缓存的配置(如过期时间)spring.cache.caffeine.spec=expireAfterWrite=5m举个Redis缓存的配置示例(application.yml):三、缓存技术选型:哪种缓存适合你的场景?Spring Boot Cache支持多种缓存技术,不同的缓存各有特点,适合不同的场景。选择合适的缓存技术,能让你的应用性能最大化。下面我们对比几种常用的缓存技术,帮你做出选择。3.1 常用缓存技术对比缓存技术核心特点优点缺点适用场景Redis分布式缓存,基于内存,支持多种数据结构(String、Hash、List等)1. 高性能(单节点QPS可达10万+)
2. 支持分布式部署,缓存一致性好
3. 支持持久化(RDB/AOF)
4. 过期策略丰富1. 需要单独部署和维护Redis服务
2. 存在网络IO开销(相比本地缓存)
3. 大Value存储可能影响性能1. 分布式系统缓存(多服务共享缓存)
2. 需要持久化的缓存场景
3. 高并发读写场景(如秒杀库存缓存)EhCache本地缓存,纯Java实现,支持内存+磁盘两级存储1. 无需单独部署,嵌入应用即可
2. 支持磁盘持久化,适合大数据量缓存
3. 支持复杂的缓存策略(如LRU、LFU)1. 不支持分布式(各节点缓存独立,易不一致)
2. 磁盘存储性能不如内存
3. 配置相对复杂1. 单体应用本地缓存
2. 需要磁盘持久化的场景(如报表数据缓存)
3. 低并发本地缓存需求Caffeine本地缓存,基于Java 8,采用W-TinyLFU淘汰算法1. 性能极佳(Java本地缓存性能天花板)
2. API简洁友好,易集成
3. 内存占用优化好,命中率高1. 不支持分布式
2. 无持久化(重启后缓存丢失)
3. 仅支持内存存储1. 本地热点数据缓存(如首页热门商品)
2. 高并发读场景(读多写少)
3. 临时缓存(无需持久化)ConcurrentMapCacheSpring内置缓存,基于ConcurrentHashMap实现1. 零依赖,Spring框架自带
2. 轻量简单,无需配置1. 功能简陋(无过期策略、无持久化)
2. 缓存数据常驻内存,可能OOM
3. 不适合生产环境1. 测试环境临时使用
2. 极简单的本地缓存场景(如开发调试)3.2 选型建议:按需选择,组合最优分布式系统优先选Redis:分布式场景下,Redis的分布式一致性和高性能是其他缓存无法替代的。例如微服务架构中,用户登录信息、商品库存等需要跨服务共享的缓存,必须用Redis。本地缓存首选Caffeine:如果是单体应用或需要本地热点缓存,Caffeine的性能优势明显。例如电商首页的热门商品列表,访问量极大且变化不频繁,用Caffeine缓存能显著减少数据库压力。复杂场景组合使用:实际开发中常组合多种缓存,比如"Redis+本地缓存"二级缓存:本地缓存减轻Redis压力,Redis保证分布式一致性。例如:用户信息先查本地Caffeine缓存,未命中再查Redis,都未命中再查数据库,查询后同时更新Redis和本地缓存。四、Spring Boot Cache的设计模式与架构思想:为什么这么设计?Spring Boot Cache的底层实现蕴含了丰富的设计模式和架构思想,这些设计让它具备高扩展性、低耦合的特点。深入理解这些设计,不仅能帮你更好地使用Spring Cache,更能在自己的项目中借鉴这些思想。4.1 核心设计模式:解决什么问题?为什么选它?4.1.1 模板方法模式(Template Method Pattern)应用场景:CacheInterceptor的invoke()方法定义了缓存操作的骨架流程。代码体现:为什么用模板方法模式?缓存操作的核心流程是固定的(查缓存→执行方法→更缓存),但具体的缓存操作(如get/put)因底层缓存技术(Redis/EhCache)而异。模板方法模式将不变的流程骨架定义在父类(CacheInterceptor),将可变的具体实现延迟到子类或接口实现(Cache接口的不同实现类)。好处:保证流程一致性,同时允许灵活替换底层缓存实现,符合"开闭原则"(对扩展开放,对修改关闭)。适用场景借鉴:当业务流程固定但具体步骤实现可变时,比如:支付流程(固定步骤:验证→扣款→通知,但不同支付方式实现不同)数据导出流程(固定步骤:查询→转换→导出,但导出格式不同)4.1.2 工厂模式(Factory Pattern)应用场景:CacheManager作为工厂,负责创建和管理Cache实例。代码体现:为什么用工厂模式?不同缓存技术的Cache实例创建逻辑不同(Redis需要连接Redis服务器,Caffeine需要初始化本地缓存容器)。工厂模式将Cache的创建逻辑封装在CacheManager中,上层代码(如CacheInterceptor)只需调用getCache()即可获取缓存实例,无需关心具体创建细节。好处:解耦对象创建和使用,更换缓存技术时只需替换CacheManager,上层代码无需修改。适用场景借鉴:当需要创建多种类型的对象,且创建逻辑复杂时,比如:日志工厂(创建FileLog、ConsoleLog、RemoteLog等不同日志实例)数据库连接工厂(创建MySQL、PostgreSQL、Oracle等不同数据库连接)4.1.3 代理模式(Proxy Pattern)应用场景:通过AOP代理为目标方法织入缓存逻辑。实现逻辑:Spring通过cacheAdvisor(缓存增强器)为加了@Cacheable等注解的方法创建代理对象,当调用目标方法时,代理对象会先执行缓存逻辑(查缓存、更缓存),再调用目标方法。为什么用代理模式?缓存逻辑是横切关注点(需要在多个方法中重复执行),如果直接写在业务方法中,会导致代码冗余和耦合。代理模式可以在不修改目标方法代码的前提下,为方法添加额外功能(缓存逻辑)。好处:业务代码与缓存逻辑分离,提高代码复用性和可维护性。适用场景借鉴:需要为方法添加通用横切功能时,比如:日志记录(调用方法前后记录日志)权限校验(调用方法前检查权限)事务管理(方法执行前后开启/提交事务)4.1.4 策略模式(Strategy Pattern)应用场景:KeyGenerator和CacheResolver接口的设计。代码体现:为什么用策略模式?不同场景下,缓存Key的生成规则可能不同(有的需要包含方法名,有的需要包含用户ID)。策略模式将Key生成算法封装为不同的KeyGenerator实现类,用户可以根据需求选择或自定义策略。好处:算法灵活切换,新增Key生成规则无需修改现有代码,符合"开闭原则"。适用场景借鉴:当有多种算法或规则可供选择时,比如:排序策略(快速排序、冒泡排序、归并排序)支付策略(支付宝、微信支付、银行卡支付)日志输出策略(控制台输出、文件输出、远程输出)4.2 核心架构思想:背后的设计哲学4.2.1 抽象与封装:屏蔽差异,聚焦业务核心思想:通过接口抽象定义缓存操作的标准,封装不同缓存技术的实现细节。具体体现:定义Cache接口统一缓存操作(get/put/evict),无论底层是Redis还是Caffeine,调用方式一致。开发者只需面向Cache和CacheManager接口编程,无需关心Redis的set命令或Caffeine的put方法。为什么这么设计?不同缓存技术的API差异很大(Redis有Jedis/Lettuce,Caffeine有自己的API),直接使用会导致代码与具体技术强耦合。抽象能降低认知成本:开发者只需学习一套接口,就能操作各种缓存。抽象能提高代码复用:缓存逻辑(如注解解析、Key生成)可以复用,无需为每种缓存技术重复开发。从中学习:当需要兼容多种实现时,先定义抽象接口,再封装具体实现。例如:消息队列抽象(定义MessageQueue接口,封装RabbitMQ、Kafka的差异)存储抽象(定义Storage接口,封装本地文件、S3、OSS的差异)4.2.2 约定优于配置:减少冗余,提升效率核心思想:提供合理的默认实现,用户只需在需要定制时才配置,而非从零开始。具体体现:默认KeyGenerator:SimpleKeyGenerator,无需配置即可生成基本Key。默认CacheManager:根据类路径依赖自动选择(有Redis依赖则用RedisCacheManager,否则用ConcurrentMapCacheManager)。注解默认值:@Cacheable的cacheNames可通过@CacheConfig类级别统一配置,无需每个方法重复写。为什么这么设计?大多数场景下,默认配置已经能满足需求,强制配置会增加开发负担。约定能减少决策成本:开发者无需纠结"Key生成器用哪个",直接用默认即可。约定不排斥定制:当默认不满足需求时,用户可通过自定义Bean覆盖默认配置。从中学习:设计框架或组件时,优先提供"开箱即用"的默认方案,同时预留定制入口。例如:ORM框架(默认主键生成策略,允许自定义)Web框架(默认端口、默认参数解析,允许配置修改)4.2.3 扩展点设计:开放扩展,拥抱变化核心思想:通过预留扩展点,允许用户根据需求自定义组件,而无需修改框架源码。具体体现:自定义KeyGenerator:实现KeyGenerator接口并注册为Bean,即可替代默认实现。自定义CacheManager:创建自定义CacheManager Bean,Spring会自动使用它而非默认实现。自定义CacheErrorHandler:实现缓存异常处理逻辑(如Redis宕机时降级到数据库)。为什么这么设计?框架无法预见所有业务场景(比如特殊的Key生成规则、复杂的缓存异常处理)。扩展点能让框架适应多样化需求,延长生命周期。扩展点遵循"好莱坞原则":"不要找我们,我们会找你"——框架主动发现并使用用户的扩展组件。从中学习:设计组件时,识别可能变化的部分并抽象为扩展点。例如:权限框架:预留自定义权限校验扩展点任务调度:预留任务执行前/后扩展点4.2.4 条件化配置:智能适配,减少配置核心思想:根据环境自动选择合适的配置,减少手动配置成本。具体体现:Spring Boot的CacheAutoConfiguration通过@Conditional注解实现条件化配置:为什么这么设计?不同环境的依赖不同(开发环境可能用Caffeine,生产环境用Redis),手动切换配置繁琐易出错。条件化配置能自动适配环境,开发者无需关心"当前用什么缓存",框架会智能选择。从中学习:当组件需要在不同环境/依赖下表现不同时,用条件化配置自动适配。例如:日志配置(有Logback依赖用Logback,有Log4j依赖用Log4j)数据库配置(有MySQL依赖用MySQL驱动,有PostgreSQL依赖用PostgreSQL驱动)五、Spring Boot Cache实战技巧:隐藏的细节与坑点使用Spring Boot Cache时,有些细节如果不注意,可能会导致缓存失效、数据不一致等问题。下面我们就来聊聊这些容易踩的坑和实用技巧。5.1 缓存Key的生成:别让Key"悄悄"出错缓存的Key是定位缓存数据的关键,如果Key生成不符合预期,缓存就会失效。Spring Boot Cache默认的KeyGenerator(SimpleKeyGenerator)生成规则是:无参数:返回SimpleKey.EMPTY一个参数:直接用参数本身作为Key多个参数:创建包含所有参数的SimpleKey对象(重写了equals和hashCode)但实际开发中,默认规则可能不够用,比如:不同方法的参数相同,可能导致Key冲突(比如getUserById(1)和getOrderById(1)的Key都是1)。需要包含方法名或类名来区分不同方法的缓存。这时候就需要自定义KeyGenerator,比如生成包含类名、方法名和参数的Key:使用时,通过keyGenerator属性指定使用自定义生成器:5.2 缓存穿透:如何避免"空查询"压垮数据库?缓存穿透是指查询一个不存在的数据(如ID=-1的用户),此时缓存不会命中,请求会直接打到数据库,当这类请求量大时,可能压垮数据库。解决方案:缓存null值。当数据库查询结果为null时,也将其存入缓存,这样后续相同请求会命中缓存,不会再访问数据库。Spring Boot Cache支持通过配置开启缓存null值:代码中通过unless属性控制是否缓存null(默认会缓存,除非显式排除):5.3 缓存雪崩:如何防止缓存集中失效?缓存雪崩是指大量缓存在同一时间过期,导致大量请求同时穿透到数据库,造成数据库压力骤增。解决方案:过期时间加随机值:让缓存的过期时间分散,避免集中过期。多级缓存:结合本地缓存和分布式缓存,本地缓存未过期时可作为兜底。缓存预热:系统启动时主动加载热点数据到缓存。以Redis为例,配置带随机值的过期时间:六、高级实战:自定义扩展与二级缓存实现6.1 自定义Redis+EhCache二级缓存:兼顾性能与一致性二级缓存是指同时使用本地缓存(如EhCache/Caffeine)和分布式缓存(如Redis),查询时先查本地缓存,未命中再查Redis,最后查数据库。这样既能利用本地缓存的高性能,又能通过Redis保证分布式一致性。实现思路:自定义Cache实现类,封装本地缓存和Redis缓存的操作。自定义CacheManager,创建二级缓存实例。查询时先查本地缓存,未命中查Redis;更新/删除时同时更新本地缓存和Redis。完整代码实现:EhCache配置文件(ehcache.xml):工作流程:6.2 扩展Redis批量缓存操作:提升批量查询性能默认的Spring Cache注解只支持单条数据的缓存操作,对于批量查询(如List
给大模型穿上“拘束衣”:从物理缺陷到 Agentic OS 的工程化实践2026-4-21
Harness + LLM Wiki + Spec 智能体驱动工作流(工程规范手册 + Onboarding 测试版)2026-4-15优化Netlify,Vercel国内访问速度:基于 enhanced-FaaS-in-China 的多路加速2026-1-13 2025火山引擎FORCE大会·冬 三大核心技术:AI原生时代的底层逻辑与实践路径2025-12-21Caffeine AsyncCache:响应式架构下(WebFlux, R2DBC, ReactiveRedis)的缓存实践2025-12-17事件驱动:WebFlux、R2DBC,Lettuce Reactive Redis与虚拟线程下的高性能Web项目构建指南2025-12-16目录0%一、Spring Boot Cache核心概念:缓存抽象的魅力1.1 核心接口:缓存世界的"规则制定者"1.2 注解驱动:一行注解搞定缓存逻辑二、Spring Boot Cache的启动与配置:从"开关"到"定制"2.1 @EnableCaching:缓存功能的"总开关"2.1.1 @EnableCaching的底层逻辑2.2 ProxyCachingConfiguration:缓存的"核心配置中心"2.2.1 核心Bean的创建过程2.3 缓存配置规则:定制你的缓存行为三、缓存技术选型:哪种缓存适合你的场景?3.1 常用缓存技术对比3.2 选型建议:按需选择,组合最优四、Spring Boot Cache的设计模式与架构思想:为什么这么设计?4.1 核心设计模式:解决什么问题?为什么选它?4.1.1 模板方法模式(Template Method Pattern)4.1.2 工厂模式(Factory Pattern)4.1.3 代理模式(Proxy Pattern)4.1.4 策略模式(Strategy Pattern)4.2 核心架构思想:背后的设计哲学4.2.1 抽象与封装:屏蔽差异,聚焦业务4.2.2 约定优于配置:减少冗余,提升效率4.2.3 扩展点设计:开放扩展,拥抱变化4.2.4 条件化配置:智能适配,减少配置五、Spring Boot Cache实战技巧:隐藏的细节与坑点5.1 缓存Key的生成:别让Key"悄悄"出错5.2 缓存穿透:如何避免"空查询"压垮数据库?5.3 缓存雪崩:如何防止缓存集中失效?六、高级实战:自定义扩展与二级缓存实现6.1 自定义Redis+EhCache二级缓存:兼顾性能与一致性6.2 扩展Redis批量缓存操作:提升批量查询性能七、总结:Spring Boot Cache的最佳实践Loading...Copyright 2020-2026HonestyAll rights reserved.湘ICP备20014902号 Honesty Blog | 从浩瀚无垠的知识中看到一缕光
本站由
提供CDN加速和云存储服务
Powered byNotionNext 4.9.3 晓梦羊®18872号