SpringBoot 多 Redis 接入
🏷️ Spring Boot Redis
spring-boot-starter-data-redis 默认仅支持配置一个 redis 服务(spring.redis.xxx)。若要配置多个,则需要手动添加相关的配置代码。 spring-boot-with-multi-redis 就是一个多 redis 的 spring-boot 示例,不过是基于 1.4.0.RELEASE 版的,部分配置方法在新版本中已经没有了。
下面是基于 2.2.13.RELEASE 版的 CacheManager
配置示例代码,另外由于不再使用 RedisTemplate 的注入,如果没有其它地方使用,相关的配置代码也可以删除。
java
@Configuration
@EnableCaching
public class MyRedisCacheConfiguration extends CachingConfigurerSupport {
@Primary
@Bean(name = "userCacheManager")
public CacheManager userCacheManager(@Qualifier("userRedisConnectionFactory") RedisConnectionFactory cf) {
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(cf);
RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext
.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext
.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
.entryTtl(Duration.ofMinutes(30));
return new RedisCacheManager(redisCacheWriter, cacheConfiguration);
}
@Bean(name = "roleCacheManager")
public CacheManager roleCacheManager(@Qualifier("roleRedisConnectionFactory") RedisConnectionFactory cf) {
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(cf);
RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext
.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext
.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
.entryTtl(Duration.ofMinutes(30));
return new RedisCacheManager(redisCacheWriter, cacheConfiguration);
}
}
附 1. 示例代码
pom.xml
这里稍有不同的是需要单独添加 jedis 依赖,否则会报 找不到 redis.clients.jedis.JedisPoolConfig
的类文件 的异常。
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.13.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>me.liujiajia</groupId>
<artifactId>multi-redis-sample</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- Jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yml
yaml
server:
port: 10101
spring:
application:
name: Multi-Redis-Application
redis:
user:
host: 127.0.0.1
port: ${redis.port:6379}
database: 10
password: 123456
role:
host: 127.0.0.1
port: ${redis.port:6379}
database: 12
password: 123456
MultiRedisApplication.java
java
package me.liujiajia.sample.redis.multi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MultiRedisApplication {
public static void main(String[] args) {
SpringApplication.run(MultiRedisApplication.class, args);
}
}
RedisProperty.java
这里使用 lombok 的 @Data
注解来简化代码。
java
package me.liujiajia.sample.redis.multi.property;
import lombok.Data;
@Data
public class RedisProperty {
private String host;
private int port;
private int database;
private String password;
}
RoleRedisProperty.java
java
package me.liujiajia.sample.redis.multi.property;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "spring.redis.role")
public class RoleRedisProperty extends RedisProperty {
}
UserRedisProperty.java
java
package me.liujiajia.sample.redis.multi.property;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "spring.redis.user")
public class UserRedisProperty extends RedisProperty {
}
MyRedisConnectionConfiguration.java
java
package me.liujiajia.sample.redis.multi.config;
import lombok.RequiredArgsConstructor;
import me.liujiajia.sample.redis.multi.property.RoleRedisProperty;
import me.liujiajia.sample.redis.multi.property.UserRedisProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
@Configuration
@RequiredArgsConstructor
public class MyRedisConnectionConfiguration {
private final UserRedisProperty userRedisProperty;
private final RoleRedisProperty roleRedisProperty;
@Primary
@Bean(name = "userRedisConnectionFactory")
public RedisConnectionFactory userRedisConnectionFactory() {
RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration();
redisConfiguration.setHostName(userRedisProperty.getHost());
redisConfiguration.setPort(userRedisProperty.getPort());
redisConfiguration.setDatabase(userRedisProperty.getDatabase());
redisConfiguration.setPassword(userRedisProperty.getPassword());
return new JedisConnectionFactory(redisConfiguration);
}
@Bean(name = "roleRedisConnectionFactory")
public RedisConnectionFactory roleRedisConnectionFactory() {
RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration();
redisConfiguration.setHostName(roleRedisProperty.getHost());
redisConfiguration.setPort(roleRedisProperty.getPort());
redisConfiguration.setDatabase(roleRedisProperty.getDatabase());
redisConfiguration.setPassword(roleRedisProperty.getPassword());
return new JedisConnectionFactory(redisConfiguration);
}
}
MyRedisCacheConfiguration.java
java
package me.liujiajia.sample.redis.multi.config;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
@Configuration
@EnableCaching
public class MyRedisCacheConfiguration extends CachingConfigurerSupport {
@Primary
@Bean(name = "userCacheManager")
public CacheManager userCacheManager(@Qualifier("userRedisConnectionFactory") RedisConnectionFactory cf) {
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(cf);
RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext
.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext
.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
.entryTtl(Duration.ofMinutes(30));
return new RedisCacheManager(redisCacheWriter, cacheConfiguration);
}
@Bean(name = "roleCacheManager")
public CacheManager roleCacheManager(@Qualifier("roleRedisConnectionFactory") RedisConnectionFactory cf) {
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(cf);
RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext
.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext
.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
.entryTtl(Duration.ofMinutes(30));
return new RedisCacheManager(redisCacheWriter, cacheConfiguration);
}
}
MyRedisTemplateConfiguration.java
提取了 RedisTemplate 的配置到单独的类,需要时可以选用。
java
package me.liujiajia.sample.redis.multi.config;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
@RequiredArgsConstructor
public class MyRedisTemplateConfiguration {
@Primary
@Bean(name = "userStringRedisTemplate")
public StringRedisTemplate userStringRedisTemplate(@Qualifier("userRedisConnectionFactory") RedisConnectionFactory cf) {
return new StringRedisTemplate(cf);
}
@Primary
@Bean(name = "userRedisTemplate")
public RedisTemplate userRedisTemplate(@Qualifier("userRedisConnectionFactory") RedisConnectionFactory cf) {
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(cf);
setSerializer(stringRedisTemplate);
return stringRedisTemplate;
}
@Bean(name = "roleStringRedisTemplate")
public StringRedisTemplate roleStringRedisTemplate(@Qualifier("roleRedisConnectionFactory") RedisConnectionFactory cf) {
return new StringRedisTemplate(cf);
}
@Bean(name = "roleRedisTemplate")
public RedisTemplate roleRedisTemplate(@Qualifier("roleRedisConnectionFactory") RedisConnectionFactory cf) {
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(cf);
setSerializer(stringRedisTemplate);
return stringRedisTemplate;
}
private void setSerializer(RedisTemplate<String, String> template) {
template.setDefaultSerializer(new GenericJackson2JsonRedisSerializer());
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new GenericJackson2JsonRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
}
}
UserService.java
java
package me.liujiajia.sample.redis.multi.service;
public interface UserService {
int getUser(int id);
int getRole(int id);
}
UserServiceImpl.java
使用 @Cacheable
注解来缓存方法的返回值,cacheNames 属性指定缓存键值的前缀,cacheManager 指定 Bean 的名称。调用有 @Cacheable
的方法时,会优先使用缓存中的结果。
另外还可以使用 @CachePut
注解更新缓存,使用 @CacheEvict
注解删除缓存。
java
package me.liujiajia.sample.redis.multi.service.impl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.liujiajia.sample.redis.multi.service.UserService;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@RequiredArgsConstructor
@Service
@Slf4j
public class UserServiceImpl implements UserService {
@Override
@Cacheable(cacheNames = "user", cacheManager = "userCacheManager")
public int getUser(int id) {
log.info("return user id = {}", id);
return id;
}
@Override
@Cacheable(cacheNames = "role", cacheManager = "roleCacheManager")
public int getRole(int id) {
log.info("return role id = {}", id);
return id;
}
}
MultiRedisTests.java
添加了几个简单的测试代码。
java
package me.liujiajia.sample.redis.multi;
import me.liujiajia.sample.redis.multi.service.UserService;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import javax.annotation.Resource;
@SpringBootTest
public class MultiRedisTests {
@Autowired
private UserService userService;
@Resource
private StringRedisTemplate userStringRedisTemplate;
@Resource
private StringRedisTemplate roleStringRedisTemplate;
@Test
public void getUserCahce() {
int userId = userService.getUser(1);
Assertions.assertEquals(userId, 1);
}
@Test
public void getRoleCahce() {
int roleId = userService.getRole(1);
Assertions.assertEquals(roleId, 1);
}
@Test
public void getUserCahceByTemplate() {
int userId = userService.getUser(10);
String cachedUserId = userStringRedisTemplate.opsForValue().get("user::10");
Assertions.assertEquals(cachedUserId, String.valueOf(userId));
}
@Test
public void getRoleCahceByTemplate() {
int roleId = userService.getRole(12);
String cachedRoleId = roleStringRedisTemplate.opsForValue().get("role::12");
Assertions.assertEquals(cachedRoleId, String.valueOf(roleId));
}
}