Spring Boot 3中配置Ehcache 2的方案及迁移兼容问题解决
Spring Boot 3 迁移 Ehcache 配置解决方案
Spring Boot 3 基于 Jakarta EE 规范,同时 Spring Context Support 6+ 移除了原 org.springframework.cache.ehcache.EhCacheCacheManager 类,需要根据是否保留旧版本 Ehcache 调整配置,以下是两种可行方案:
方案一:升级到 Ehcache 3.x(推荐)
Ehcache 2.x 已停止维护,升级到 3.x 不仅能适配 Spring Boot 3,还能获得性能提升和安全更新。
1. 调整依赖(Maven 示例)
替换原 Ehcache 2 依赖为 Ehcache 3:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>org.ehcache</groupId> <artifactId>ehcache</artifactId> </dependency>
2. 迁移 Ehcache XML 配置
Ehcache 3 使用全新的 XML Schema,需要将原 configFile.xml 调整为符合 3.x 规范的格式,示例:
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.ehcache.org/v3" xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd"> <!-- 定义缓存实例,替换为你原有的缓存配置 --> <cache alias="userCache"> <key-type>java.lang.Long</key-type> <value-type>com.example.User</value-type> <expiry> <ttl unit="hours">24</ttl> </expiry> <heap unit="entries">1000</heap> </cache> </config>
3. 配置 Spring Cache
自动配置(最简方式)
在 application.properties 中指定配置文件路径,Spring Boot 会自动创建适配的 CacheManager:
spring.cache.jcache.config=classpath:/configFile.xml
自定义 CacheManager(如需扩展)
如果需要手动控制 CacheManager 创建逻辑,可以编写配置类:
import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.jcache.JCacheCacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.cache.Caching; import javax.cache.CachingProvider; import javax.cache.CacheManager; import java.net.URL; @Configuration @EnableCaching class Config { @Bean public org.springframework.cache.CacheManager cacheManager() { CachingProvider provider = Caching.getCachingProvider(); URL configUrl = getClass().getResource("/configFile.xml"); CacheManager jcacheManager = provider.getCacheManager(configUrl, getClass().getClassLoader()); return new JCacheCacheManager(jcacheManager); } }
方案二:继续使用 Ehcache 2.x(不推荐)
如果因业务限制必须保留原 Ehcache 2.x 配置,需要手动实现 Spring Cache 与 Ehcache 2 的适配:
1. 保留依赖
确保引入 Ehcache 2.x 的最后稳定版本:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>2.10.9.2</version> </dependency>
2. 自定义 CacheManager 适配类
由于原 EhCacheCacheManager 被移除,需要手动实现适配逻辑:
import org.springframework.cache.Cache; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.support.AbstractCacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Ehcache; import net.sf.ehcache.Element; import java.net.URL; import java.util.Collection; import java.util.stream.Collectors; @Configuration @EnableCaching class Config { @Bean(destroyMethod = "shutdown") public CacheManager ehCacheManager() { URL url = getClass().getResource("/configFile.xml"); return net.sf.ehcache.CacheManager.newInstance(url); } @Bean public org.springframework.cache.CacheManager cacheManager(CacheManager ehCacheManager) { return new AbstractCacheManager() { @Override protected Collection<? extends Cache> loadCaches() { // 将 Ehcache 2 的缓存实例适配为 Spring Cache 接口 return ehCacheManager.getCacheNames().stream() .map(name -> new Ehcache2SpringCacheAdapter(ehCacheManager.getCache(name))) .collect(Collectors.toList()); } }; } // 自定义适配类,实现 Spring Cache 接口 static class Ehcache2SpringCacheAdapter implements Cache { private final Ehcache ehcache; public Ehcache2SpringCacheAdapter(Ehcache ehcache) { this.ehcache = ehcache; } @Override public String getName() { return ehcache.getName(); } @Override public Object getNativeCache() { return ehcache; } @Override public ValueWrapper get(Object key) { Element element = ehcache.get(key); return element != null ? () -> element.getObjectValue() : null; } @Override public <T> T get(Object key, Class<T> type) { Element element = ehcache.get(key); if (element == null) return null; Object value = element.getObjectValue(); if (type != null && !type.isInstance(value)) { throw new IllegalStateException("缓存值类型不匹配,预期:" + type.getName()); } return (T) value; } @Override public void put(Object key, Object value) { ehcache.put(new Element(key, value)); } @Override public ValueWrapper putIfAbsent(Object key, Object value) { Element element = ehcache.putIfAbsent(new Element(key, value)); return element != null ? () -> element.getObjectValue() : null; } @Override public void evict(Object key) { ehcache.remove(key); } @Override public void clear() { ehcache.removeAll(); } } }
注意:Ehcache 2.x 已停止维护,存在未修复的安全漏洞,仅建议临时过渡使用,长期应升级到 Ehcache 3.x。
内容的提问来源于stack exchange,提问作者Sador La
相关产品推荐
相关产品推荐

