Spring @Cacheable如何适配Redis读写分离副本?
实现Redis缓存读写分离(主从连接)并兼容@Cacheable注解
完全可以实现,核心思路是配置两个独立的CacheManager,分别绑定主节点(读写)和从节点(只读)的连接工厂,再通过缓存注解指定对应的CacheManager来区分读写操作。
1. 配置两个Lettuce连接工厂
先定义主节点(用于缓存写/更新/删除)和从节点(仅用于缓存读)的连接工厂Bean:
@Configuration @EnableCaching public class CacheConfiguration extends CachingConfig { // 主节点连接工厂(读写),可沿用原有自动配置参数或自定义配置 @Bean("lettuceMasterConnectionFactory") public LettuceConnectionFactory lettuceMasterConnectionFactory(RedisProperties redisProperties) { RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(redisProperties.getHost(), redisProperties.getPort()); config.setPassword(RedisPassword.of(redisProperties.getPassword())); return new LettuceConnectionFactory(config); } // 从节点连接工厂(只读),配置副本节点地址 @Bean("lettuceSlaveConnectionFactory") public LettuceConnectionFactory lettuceSlaveConnectionFactory() { RedisStandaloneConfiguration config = new RedisStandaloneConfiguration("redis-slave-host", 6379); config.setPassword(RedisPassword.of("slave-password")); return new LettuceConnectionFactory(config); } // 后续CacheManager配置... }
2. 配置两个对应的CacheManager
分别创建主从对应的CacheManager,保留原有TTL配置逻辑:
// 主节点CacheManager,用于写/更新/删除操作 @Bean("masterCacheManager") public CacheManager masterCacheManager(@Qualifier("lettuceMasterConnectionFactory") LettuceConnectionFactory masterFactory) { RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig(); return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(masterFactory) .cacheDefaults(defaultConfig) .withCacheConfiguration("myCache", defaultConfig.entryTtl(Duration.ofMinutes(5))) .withCacheConfiguration("someOtherCache", defaultConfig.entryTtl(Duration.ofMinutes(10))) .build(); } // 从节点CacheManager,仅用于读操作 @Bean("slaveCacheManager") public CacheManager slaveCacheManager(@Qualifier("lettuceSlaveConnectionFactory") LettuceConnectionFactory slaveFactory) { RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig(); return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(slaveFactory) .cacheDefaults(defaultConfig) .withCacheConfiguration("myCache", defaultConfig.entryTtl(Duration.ofMinutes(5))) .withCacheConfiguration("someOtherCache", defaultConfig.entryTtl(Duration.ofMinutes(10))) .build(); }
3. 修改缓存注解指定CacheManager
在业务方法上,给@Cacheable(读操作)指定从节点的CacheManager;写/更新/删除操作(如@CachePut、@CacheEvict)指定主节点的CacheManager:
// 读操作:使用从节点CacheManager @Cacheable(cacheNames = "myCache", key = "#token", cacheManager = "slaveCacheManager") public String getUserByToken(String token) { return externalService.getUserFromToken(token); } // 更新缓存操作:使用主节点CacheManager @CachePut(cacheNames = "myCache", key = "#token", cacheManager = "masterCacheManager") public String updateUserToken(String token, UserInfo userInfo) { externalService.updateUser(token, userInfo); return userInfo.toString(); } // 删除缓存操作:使用主节点CacheManager @CacheEvict(cacheNames = "myCache", key = "#token", cacheManager = "masterCacheManager") public void invalidateUserToken(String token) { externalService.invalidateToken(token); }
补充说明
- 若希望大部分读操作默认用从节点,可给
slaveCacheManager添加@Primary注解,未指定cacheManager的@Cacheable会自动使用从节点;写操作需显式指定masterCacheManager。 - 确保从节点Redis配置为只读模式,避免误写操作。
内容的提问来源于stack exchange,提问作者Alexis
相关产品推荐
相关产品推荐

