Spring Boot项目中能否给Service字段加@Cacheable注解实现Map缓存?
结论:不可以直接给Service类的
cachedMap字段添加@Cacheable注解 Spring缓存注解不支持直接作用于类字段,原因如下:
Spring的缓存功能基于AOP代理实现,@Cacheable、@CachePut、@CacheEvict等缓存注解仅支持标注在类或方法上,只有被代理对象调用的标注注解的方法才会触发缓存逻辑,字段上标注的注解不会被缓存切面识别,不会产生任何效果。
正确实现方案
首先第一步需要在项目启动类或缓存配置类上添加@EnableCaching注解开启缓存功能,示例:
@SpringBootApplication @EnableCaching public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
方案1:将整个Map作为单个缓存项(适合全量更新多的场景)
该方案将整份Map数据作为一个缓存条目存储,实现简单:
import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.Map; @Service public class MapService { // 缓存名称自定义为mapCache,固定key为fullMap @Cacheable(value = "mapCache", key = "'fullMap'") public Map<String, Object> getFullMap() { // 缓存未命中时的初始逻辑,可根据业务调整,比如从数据库加载初始数据 return new HashMap<>(); } // 更新后刷新缓存 @CachePut(value = "mapCache", key = "'fullMap'") public Map<String, Object> updateMap(Map<String, Object> data) { Map<String, Object> cachedMap = getFullMap(); cachedMap.putAll(data); return cachedMap; } public Object getFromMap(String key) { return getFullMap().get(key); } }
方案2:将Map的每个键值对作为独立缓存项(适合单key查询多的场景)
该方案把每个key对应的value单独存储为缓存条目,查询性能更高:
import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import java.util.Map; @Service public class MapService { @Cacheable(value = "mapItemCache", key = "#key") public Object getFromMap(String key) { // 缓存未命中时的返回逻辑,可根据业务调整 return null; } public void updateMap(Map<String, Object> data) { data.forEach(this::saveSingleItem); } @CachePut(value = "mapItemCache", key = "#key") public Object saveSingleItem(String key, Object value) { return value; } }
注意事项
- 单实例部署时,Spring Boot默认使用
ConcurrentHashMap作为缓存实现,完全满足需求;多实例部署需要保证缓存一致性的话,直接引入Redis等分布式缓存的starter依赖即可,Spring Boot会自动适配,无需修改业务代码。 - 不要在类内部直接调用带缓存注解的方法,内部调用走的是当前类实例而非代理对象,会导致缓存逻辑失效,需要调用的话可以通过
ApplicationContext获取代理对象再调用,或者将缓存方法拆分到独立的Bean中。 - 如果你确实想自己维护Service中的
cachedMap字段作为本地缓存,不需要使用Spring缓存注解,只要将字段实现类换成ConcurrentHashMap保证线程安全即可,缺点是重启后数据丢失,多实例部署时各个实例缓存不一致。
内容的提问来源于stack exchange,提问作者Leah
相关产品推荐
相关产品推荐

