集成EHCache+Terracotta+Spring时使用@CacheEvict遇UnsupportedOperationException
解决Ehcache 3.4.0集群模式下@CacheEvict(allEntries=true)抛出UnsupportedOperationException的问题
我之前也碰到过一模一样的情况,这个异常在Ehcache 3.x早期集群版本的JSR107集成里是个典型的功能未完善问题,下面给你具体的解决思路和可行方案:
问题根源
Ehcache 3.4.0的JCache(JSR107)实现在**集群存储(ClusteredStore)**场景下,没有完成allEntries=true对应的全量缓存清除逻辑,底层的ClusteredStore类直接抛出了UnsupportedOperationException: Implement me,这是官方当时的功能遗漏。
解决方案
方案1:升级Ehcache到3.5.0及以上版本
官方在Ehcache 3.5.0版本中修复了这个JCache集群下的批量清除问题,升级是最彻底的解决方式。注意要同步升级Terracotta服务器版本,确保和Ehcache版本兼容(比如Ehcache 3.5.0对应Terracotta Server 5.3.0+)。
方案2:不升级版本,改用原生API手动清除
如果暂时无法升级,可以绕过JSR107注解的限制,直接使用Ehcache的原生API来实现全量清除:
- 在Spring组件中注入JCache的
CacheManager - 将其转换为Ehcache原生的
Cache实例,调用clear()方法
示例代码:
import javax.cache.Cache; import javax.cache.CacheManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class CacheClearService { @Autowired private CacheManager jCacheManager; public void clearAllEntriesInCache(String cacheName) { Cache<Object, Object> jCache = jCacheManager.getCache(cacheName); if (jCache != null) { // 转换为Ehcache原生Cache实例 org.ehcache.Cache<Object, Object> ehcache = jCache.unwrap(org.ehcache.Cache.class); // 调用原生clear方法,集群环境下可正常执行全量清除 ehcache.clear(); } } }
然后在需要清除缓存的业务方法里,直接调用这个服务方法即可,替代@CacheEvict(allEntries=true)的作用。
方案3:核对Spring配置的正确性
虽然你说已经完成集群集成,但还是可以再确认下Spring Cache配置是否正确关联了集群模式的Ehcache实例,避免误用本地缓存实例:
示例正确的集群CacheManager配置:
import org.ehcache.clustered.client.config.ClusteredCacheManagerConfiguration; import org.ehcache.clustered.client.config.builders.ClusteredCacheManagerConfigurationBuilder; import org.ehcache.config.builders.CacheManagerBuilder; import org.ehcache.core.EhcacheManager; import org.springframework.cache.jcache.JCacheCacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.cache.Caching; import java.net.URI; @Configuration public class CacheConfig { @Bean public JCacheCacheManager cacheManager() { // 配置Terracotta集群地址 URI terracottaUri = URI.create("terracotta://localhost:9410/myClusterCacheManager"); ClusteredCacheManagerConfiguration clusterConfig = ClusteredCacheManagerConfigurationBuilder.cluster(terracottaUri).build(); // 创建集群模式的EhcacheManager EhcacheManager ehcacheManager = (EhcacheManager) CacheManagerBuilder.newCacheManagerBuilder() .with(clusterConfig) .build(true); // 转换为Spring兼容的JCacheCacheManager return new JCacheCacheManager(Caching.getCachingProvider().getCacheManager( ehcacheManager.getURI(), ehcacheManager.getClass().getClassLoader())); } }
内容的提问来源于stack exchange,提问作者Fibman
相关产品推荐
相关产品推荐

