You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 20:06:02