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

Spring中@Cacheable无法识别动态设置的cacheResolver值如何解决?

问题根因

你当前的AOP方案不生效是因为Spring缓存模块对注解的解析发生在Bean初始化阶段:Spring会在应用启动时通过AnnotationCacheOperationSource扫描所有带@Cacheable的方法,提前把注解属性解析为CacheOperation元数据缓存起来,后续方法调用时直接读取预解析的元数据,不会再重复读取方法上的注解内容。你在运行时通过反射修改注解memberValues的时机太晚,修改后的内容根本不会被Spring缓存逻辑用到。

解决方案

你提到所有方法的cacheResolver值都相同,直接用Spring原生提供的全局默认配置即可,不需要做任何注解hack,方案如下:

最优方案:配置全局默认CacheResolver

你只需要实现CachingConfigurer接口,重写cacheResolver方法,将你自定义的cacheableResolver设为全局默认值,所有未显式指定cacheResolver属性的@Cacheable注解都会自动使用该Resolver:

import org.springframework.cache.annotation.CachingConfigurer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.context.annotation.Configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

@Configuration
@EnableCaching
public class CacheConfiguration implements CachingConfigurer {

    @Autowired
    @Qualifier("cacheableResolver")
    private CacheResolver customCacheResolver;

    @Override
    public CacheResolver cacheResolver() {
        // 返回你自定义的CacheResolver作为全局默认
        return customCacheResolver;
    }

    // 如果需要自定义CacheManager、KeyGenerator等也可以重写对应方法
}

修改后你的测试代码不需要做任何改动,@Cacheable(value = "test")会自动使用你配置的cacheableResolver处理缓存逻辑。

可选方案:自定义CacheResolver做动态分发

如果你后续需要更灵活的缓存策略,比如根据缓存名、方法参数等运行时信息选择不同的缓存源,可以直接在你自定义的CacheResolver里写分发逻辑,不需要修改任何业务代码的注解:

import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.interceptor.CacheOperationInvocationContext;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.Collections;

@Component("cacheableResolver")
public class CustomCacheResolver implements CacheResolver {

    // 注入你需要的多个CacheManager
    private final CacheManager defaultCacheManager;
    private final CacheManager remoteCacheManager;

    public CustomCacheResolver(CacheManager defaultCacheManager, CacheManager remoteCacheManager) {
        this.defaultCacheManager = defaultCacheManager;
        this.remoteCacheManager = remoteCacheManager;
    }

    @Override
    public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
        String cacheName = context.getOperation().getCacheNames().iterator().next();
        // 动态判断使用哪个缓存源
        if (cacheName.startsWith("remote_")) {
            return Collections.singleton(remoteCacheManager.getCache(cacheName));
        }
        return Collections.singleton(defaultCacheManager.getCache(cacheName));
    }
}

不推荐的方案:提前修改注解属性

如果你一定要通过修改注解属性实现需求,需要把修改时机提前到Spring解析缓存注解之前,通过BeanPostProcessor在Bean初始化阶段修改方法上的@Cacheable属性,运行时AOP修改是无效的。该方案属于反射hack,依赖Spring内部实现,版本升级可能失效,因此不推荐使用。


内容的提问来源于stack exchange,提问作者futurexv

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 14:09:03