EhCache 3缓存无法命中求助:使用对象作为键值时缓存失效
问题现象
使用EhCache 3结合Spring Boot 3时,缓存始终无法命中,每次调用带@Cacheable注解的方法都会打印CacheInterceptor - No cache entry for key日志,并重新生成缓存条目,无论参数组合如何都无法匹配已有缓存。
环境与配置
- 带
@Cacheable的服务方法包含两个String类型参数和一个POJO类型LangAndMarket作为缓存键 - 技术栈:Spring Boot 3、EhCache 3.10.8(jakarta分类器)
- 缓存通过XML文件定义
- 已开启
ehcache和org.springframework.cache的TRACE级日志
配置类
@Configuration @EnableCaching public class CacheConfig { @Autowired private javax.cache.CacheManager cacheManager; }
application.yml
spring: cache: jcache: config: classpath:ehcache.xml
ehcache.xml
... <cache alias="cmsLabelsCache"> <expiry> <ttl unit="seconds">10</ttl> </expiry> <heap unit="entries">10000</heap> </cache> ....
服务类
@Service public class CMSPropertiesService { @Cacheable(value = "cmsLabelsCache", key = "{#cmsSpecificRequest, #langAndMarket, #labelKey}") public String getLabelWithReferences(@NotNull String cmsSpecificRequest, @NotNull LangAndMarket langAndMarket, @NotNull String labelKey) { String label = "[" + cmsSpecificRequest + ", " + langAndMarket.toString() + ", " + labelKey + "]"; return label; }
LangAndMarket类
public static class LangAndMarket { private String lang; private String market; ... getters, setters, constructors. lang and market @NotNull
可能的原因及解决办法
LangAndMarket未实现equals()和hashCode()
Spring缓存的键匹配依赖对象的equals和hashCode方法,默认的Object实现仅比较引用地址——即使两个LangAndMarket实例的lang和market值完全相同,也会被视为不同的键。必须基于lang和market字段手动实现这两个方法:@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; LangAndMarket that = (LangAndMarket) o; return Objects.equals(lang, that.lang) && Objects.equals(market, that.market); } @Override public int hashCode() { return Objects.hash(lang, market); }验证缓存键生成逻辑
查看TRACE日志中CacheInterceptor打印的实际键值,确认相同参数是否生成一致的键。若键内容不一致,需检查SpEL表达式{#cmsSpecificRequest, #langAndMarket, #labelKey}是否存在解析问题。简化CacheManager配置
当前自定义CacheConfig仅注入了javax.cache.CacheManager,可尝试去掉该配置类,仅保留@EnableCaching注解,让Spring Boot自动加载application.yml中配置的ehcache.xml,避免手动注入引发的配置冲突。检查键类型兼容性
EhCache 3对缓存键的序列化有要求,确保复合键(三个参数组成的集合)能被正确识别。实现equals和hashCode是保证键一致性的基础,若仍有问题,可尝试显式指定键的序列化策略。
内容的提问来源于stack exchange,提问作者ssimm

