Spring Boot中在@Configuration类中注册自定义CacheResolver的惯用方式
我之前也碰到过几乎一模一样的场景——多个CacheManager冲突,还有第三方库的@Cacheable注解没法修改,不想在每处注解里硬指定缓存管理器或解析器,确实头疼!你之前用CachingConfigurator的路子走偏了,其实Spring有更直接、更符合 idiomatic 的方式来解决这个问题,完全不用跟那个接口死磕。
正确的全局配置步骤
核心思路是:定义自定义CacheResolver为普通Bean,然后通过@EnableCaching指定它作为全局默认的缓存解析器,这样所有没显式指定cacheResolver的@Cacheable(包括第三方库的)都会自动用它。
1. 先把两个CacheManager定义为Bean(带清晰标识)
首先确保你的两个缓存管理器都被正确注册为Spring Bean,用名称或者@Qualifier区分开,比如:
@Configuration public class CacheConfig { // 第一个缓存管理器:比如用于自己代码的缓存 @Bean("appCacheManager") public CacheManager appCacheManager() { // 这里替换成你的实际配置,比如Caffeine、Redis等 return new CaffeineCacheManager("user-cache", "order-cache"); } // 第二个缓存管理器:用于第三方库的缓存 @Bean("libCacheManager") public CacheManager libCacheManager() { // 第三方库对应的缓存配置 return RedisCacheManager.builder(redisConnectionFactory()) .cacheDefaults(RedisCacheConfiguration.defaultCacheConfig()) .build(); } }
2. 定义自定义CacheResolverBean(正常依赖注入两个CacheManager)
接下来创建你的自定义解析器,直接在@Bean方法里注入两个CacheManager,完全不用管什么接口的无参方法限制:
@Bean("customCacheResolver") public CacheResolver customCacheResolver( @Qualifier("appCacheManager") CacheManager appCacheManager, @Qualifier("libCacheManager") CacheManager libCacheManager) { return new MyCustomCacheResolver(appCacheManager, libCacheManager); }
这里的MyCustomCacheResolver就是你自己实现的路由逻辑,比如根据缓存名称、方法所在包名来判断用哪个CacheManager:
public class MyCustomCacheResolver implements CacheResolver { private final CacheManager appCacheManager; private final CacheManager libCacheManager; public MyCustomCacheResolver(CacheManager appCacheManager, CacheManager libCacheManager) { this.appCacheManager = appCacheManager; this.libCacheManager = libCacheManager; } @Override public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) { // 这里写你的路由逻辑,比如: // 1. 获取当前缓存注解的缓存名称 String cacheName = context.getOperation().getCacheNames().iterator().next(); // 2. 根据缓存名称前缀判断用哪个管理器(比如第三方库的缓存都以"lib-"开头) if (cacheName.startsWith("lib-")) { return Collections.singleton(libCacheManager.getCache(cacheName)); } // 3. 默认用自己的缓存管理器 return Collections.singleton(appCacheManager.getCache(cacheName)); } }
3. 指定全局默认的CacheResolver
最后,在你的主配置类(或者任何带有@EnableCaching的类)上,通过cacheResolver参数指定我们刚才定义的解析器Bean名称:
@SpringBootApplication @EnableCaching(cacheResolver = "customCacheResolver") // 关键!指定全局默认解析器 public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } }
为什么之前的CachingConfigurator方式不好用?
你之前碰到的问题本质是CachingConfigurator接口的设计限制:它要求cacheResolver()方法是无参的,因为Spring会直接调用这个无参方法来获取解析器实例,没法通过方法参数注入其他Bean。这种方式只适合完全不依赖其他Bean的简单场景,显然不符合你需要两个CacheManager的需求,所以官方其实更推荐用@EnableCaching的参数来指定全局默认,而不是去实现那个接口。
最终效果
这样配置之后:
- 你自己代码里的
@Cacheable不用加任何额外参数,自动用你的自定义解析器; - 第三方库的
@Cacheable(因为你没法修改)也会自动使用这个全局解析器,完全不用你逐个修改注解。
备注:内容来源于stack exchange,提问作者Mitch Kent

