Spring Cache集成Infinispan:缓存自动创建与断连降级实现方案咨询
实现方案说明
完全可以通过自定义注解+Aspect实现需求,同时也可以通过扩展Spring Cache的核心组件(CacheManager)来更优雅地适配这两个需求,以下是具体实现方式:
方案一:自定义注解 + AOP 实现
这种方式灵活性高,适合需要额外定制缓存逻辑的场景,步骤如下:
1. 定义自定义缓存注解
创建一个和@Cacheable功能类似的自定义注解,用于标记需要缓存的方法:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface RemoteCacheable { // 缓存名称 String cacheName(); // 自定义缓存key(可选,默认基于方法名+参数生成) String key() default ""; }
2. 编写AOP切面处理缓存逻辑
在切面中完成「缓存自动创建」「连接降级」「缓存读写」的核心逻辑:
@Aspect @Component public class RemoteCacheAspect { @Autowired private InfinispanClient infinispanClient; @Around("@annotation(remoteCacheable)") public Object handleCache(ProceedingJoinPoint joinPoint, RemoteCacheable remoteCacheable) throws Throwable { String cacheName = remoteCacheable.cacheName(); // 生成缓存key:优先用注解指定的key,否则用方法名+参数拼接 String key = StringUtils.isEmpty(remoteCacheable.key()) ? generateDefaultKey(joinPoint) : remoteCacheable.key(); try { // 步骤1:获取或自动创建缓存(基于Infinispan服务器预设模板) Cache<Object, Object> cache = infinispanClient.getOrCreateCache(cacheName); // 步骤2:查询缓存,命中则直接返回 Object cachedValue = cache.get(key); if (cachedValue != null) { return cachedValue; } // 步骤3:缓存未命中,执行目标慢服务方法 Object result = joinPoint.proceed(); // 步骤4:将结果存入缓存 cache.put(key, result); return result; } catch (InfinispanConnectionException e) { // 连接失败时直接降级执行慢服务 return joinPoint.proceed(); } } // 生成默认缓存key的工具方法 private String generateDefaultKey(ProceedingJoinPoint joinPoint) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); String methodName = signature.getMethod().getName(); Object[] args = joinPoint.getArgs(); return methodName + Arrays.toString(args); } }
3. 封装Infinispan客户端操作
实现getOrCreateCache方法,调用Infinispan API完成缓存的自动创建:
@Service public class InfinispanClient { private final RemoteCacheManager remoteCacheManager; // 构造注入RemoteCacheManager public InfinispanClient(RemoteCacheManager remoteCacheManager) { this.remoteCacheManager = remoteCacheManager; } public Cache<Object, Object> getOrCreateCache(String cacheName) { // 检查缓存是否存在,不存在则基于服务器预设模板创建 if (!remoteCacheManager.getCacheNames().contains(cacheName)) { // "default-template"是Infinispan服务器预先配置好的缓存模板 remoteCacheManager.administration().createCache(cacheName, "default-template"); } return remoteCacheManager.getCache(cacheName); } }
方案二:扩展Spring Cache的CacheManager(推荐)
这种方式更贴合Spring Cache的原生生态,无需替换原有@Cacheable注解,侵入性更低:
1. 自定义CacheManager
继承Spring提供的InfinispanCacheManager,重写getCache方法,实现缓存自动创建和连接降级逻辑:
public class InfinispanAutoCreatingCacheManager extends InfinispanCacheManager { private final String defaultTemplateName; public InfinispanAutoCreatingCacheManager(RemoteCacheManager remoteCacheManager, String defaultTemplateName) { super(remoteCacheManager); this.defaultTemplateName = defaultTemplateName; } @Override public Cache getCache(String name) { Cache cache = super.getCache(name); if (cache == null) { try { // 基于服务器模板创建缓存 getRemoteCacheManager().administration().createCache(name, defaultTemplateName); cache = super.getCache(name); } catch (CacheException e) { // 连接失败时返回空实现的Cache,让Spring直接执行目标方法 return new NoOpCache(name); } } return cache; } // 空实现的Cache,所有缓存操作都不生效 private static class NoOpCache implements Cache { private final String name; public NoOpCache(String name) { this.name = name; } @Override public String getName() { return name; } @Override public Object getNativeCache() { return null; } @Override public ValueWrapper get(Object key) { return null; } @Override public <T> T get(Object key, Class<T> type) { return null; } @Override public <T> T get(Object key, Callable<T> valueLoader) { try { return valueLoader.call(); } catch (Exception e) { throw new ValueRetrievalException(key, valueLoader, e); } } @Override public void put(Object key, Object value) {} // 其他缓存操作方法均做空实现或返回默认值 } }
2. 配置自定义CacheManager
在Spring配置类中注册自定义的CacheManager:
@Configuration @EnableCaching public class CacheConfig { @Bean public RemoteCacheManager remoteCacheManager() { // 配置Infinispan远程连接 return new RemoteCacheManager( new ConfigurationBuilder() .addServer() .host("localhost") .port(11222) .build() ); } @Bean public CacheManager cacheManager(RemoteCacheManager remoteCacheManager) { // 指定Infinispan服务器预设的缓存模板名称 return new InfinispanAutoCreatingCacheManager(remoteCacheManager, "default-template"); } }
配置完成后,直接使用原生的@Cacheable注解即可,所有需求逻辑都由自定义CacheManager自动处理。
方案对比
- 自定义注解+AOP:灵活性强,可快速添加额外定制逻辑,但需要替换原有注解,侵入性稍高。
- 扩展CacheManager:完全贴合Spring Cache原生机制,无需修改业务代码,侵入性低,推荐用于大多数场景。
内容的提问来源于stack exchange,提问作者Zoltan Altfatter
相关产品推荐
相关产品推荐

