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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 05:25:57