乐趣区

SpringBoot系列教程之RedisTemplate 基本配置说明文档

更多 Spring 文章,欢迎点击 一灰灰 Blog-Spring 专题

在 Spring 的应用中,redis 可以算是基础操作了。那么想要玩转 redis,我们需要知道哪些知识点呢?

redis 配置,默认,非默认,集群,多实例,连接池参数等
redis 读写操作,RedisTemplate 的基本使用姿势
几种序列化方式对比

本篇博文为 redis 系列的开篇,将介绍最基本的配置
原文链接: 181029-SpringBoot 高级篇 Redis 之基本配置

I. redis 基本配置
1. 默认配置
最简单的使用其实开箱即可用,添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
本机启动 redis,一切采用默认的配置(host:127.0.0.1, port:6379, 无密码 )
然后就可以愉快的玩耍了,可以直接注入 redisTemplate 实例,进行各种读写操作
@SpringBootApplication
public class Application {

public Application(RedisTemplate<String, String> redisTemplate) {
redisTemplate.opsForValue().set(“hello”, “world”);
String ans = redisTemplate.opsForValue().get(“hello”);
Assert.isTrue(“world”.equals(ans));
}

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2. 自定义配置参数
前面是默认的配置参数,在实际的使用中,一般都会修改这些默认的配置项,如果我的应用中,只有一个 redis,那么完全可以只修改默认的配置参数
修改配置文件: application.yml
spring:
redis:
host: 127.0.0.1
port: 6379
password:
database: 0
lettuce:
pool:
max-active: 32
max-wait: 300ms
max-idle: 16
min-idle: 8
使用和前面没有什么区别,直接通过注入 RedisTemplate 来操作即可,需要额外注意的是设置了连接池的相关参数,需要额外引入依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
3. 多 redis 配置
依赖多个不同的 redis,也就是说我的项目需要从多个 redis 实例中获取数据,这种时候,就不能直接使用默认的,需要我们自己来声明 ConnectionFactory 和 RedisTemplate
配置如下
spring:
redis:
host: 127.0.0.1
port: 6379
password:
lettuce:
pool:
max-active: 32
max-wait: 300
max-idle: 16
min-idle: 8
database: 0
local-redis:
host: 127.0.0.1
port: 6379
database: 0
password:
lettuce:
pool:
max-active: 16
max-wait: 100
max-idle: 8
min-idle: 4
对应的配置类,采用 Lettuce,基本设置如下,套路都差不多,先读取配置,初始化 ConnectionFactory,然后创建 RedisTemplate 实例,设置连接工厂
@Configuration
public class RedisAutoConfig {

@Bean
public LettuceConnectionFactory defaultLettuceConnectionFactory(RedisStandaloneConfiguration defaultRedisConfig,
GenericObjectPoolConfig defaultPoolConfig) {
LettuceClientConfiguration clientConfig =
LettucePoolingClientConfiguration.builder().commandTimeout(Duration.ofMillis(100))
.poolConfig(defaultPoolConfig).build();
return new LettuceConnectionFactory(defaultRedisConfig, clientConfig);
}

@Bean
public RedisTemplate<String, String> defaultRedisTemplate(
LettuceConnectionFactory defaultLettuceConnectionFactory) {
RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(defaultLettuceConnectionFactory);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}

@Bean
@ConditionalOnBean(name = “localRedisConfig”)
public LettuceConnectionFactory localLettuceConnectionFactory(RedisStandaloneConfiguration localRedisConfig,
GenericObjectPoolConfig localPoolConfig) {
LettuceClientConfiguration clientConfig =
LettucePoolingClientConfiguration.builder().commandTimeout(Duration.ofMillis(100))
.poolConfig(localPoolConfig).build();
return new LettuceConnectionFactory(localRedisConfig, clientConfig);
}

@Bean
@ConditionalOnBean(name = “localLettuceConnectionFactory”)
public RedisTemplate<String, String> localRedisTemplate(LettuceConnectionFactory localLettuceConnectionFactory) {
RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(localLettuceConnectionFactory);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}

@Configuration
@ConditionalOnProperty(name = “host”, prefix = “spring.local-redis”)
public static class LocalRedisConfig {
@Value(“${spring.local-redis.host:127.0.0.1}”)
private String host;
@Value(“${spring.local-redis.port:6379}”)
private Integer port;
@Value(“${spring.local-redis.password:}”)
private String password;
@Value(“${spring.local-redis.database:0}”)
private Integer database;

@Value(“${spring.local-redis.lettuce.pool.max-active:8}”)
private Integer maxActive;
@Value(“${spring.local-redis.lettuce.pool.max-idle:8}”)
private Integer maxIdle;
@Value(“${spring.local-redis.lettuce.pool.max-wait:-1}”)
private Long maxWait;
@Value(“${spring.local-redis.lettuce.pool.min-idle:0}”)
private Integer minIdle;

@Bean
public GenericObjectPoolConfig localPoolConfig() {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMaxTotal(maxActive);
config.setMaxIdle(maxIdle);
config.setMinIdle(minIdle);
config.setMaxWaitMillis(maxWait);
return config;
}

@Bean
public RedisStandaloneConfiguration localRedisConfig() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
config.setHostName(host);
config.setPassword(RedisPassword.of(password));
config.setPort(port);
config.setDatabase(database);
return config;
}
}

@Configuration
public static class DefaultRedisConfig {
@Value(“${spring.redis.host:127.0.0.1}”)
private String host;
@Value(“${spring.redis.port:6379}”)
private Integer port;
@Value(“${spring.redis.password:}”)
private String password;
@Value(“${spring.redis.database:0}”)
private Integer database;

@Value(“${spring.redis.lettuce.pool.max-active:8}”)
private Integer maxActive;
@Value(“${spring.redis.lettuce.pool.max-idle:8}”)
private Integer maxIdle;
@Value(“${spring.redis.lettuce.pool.max-wait:-1}”)
private Long maxWait;
@Value(“${spring.redis.lettuce.pool.min-idle:0}”)
private Integer minIdle;

@Bean
public GenericObjectPoolConfig defaultPoolConfig() {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMaxTotal(maxActive);
config.setMaxIdle(maxIdle);
config.setMinIdle(minIdle);
config.setMaxWaitMillis(maxWait);
return config;
}

@Bean
public RedisStandaloneConfiguration defaultRedisConfig() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
config.setHostName(host);
config.setPassword(RedisPassword.of(password));
config.setPort(port);
config.setDatabase(database);
return config;
}
}
}
测试类如下,简单的演示下两个 template 的读写
@SpringBootApplication
public class Application {

public Application(RedisTemplate<String, String> localRedisTemplate, RedisTemplate<String, String>
defaultRedisTemplate)
throws InterruptedException {
// 10s 的有效时间
localRedisTemplate.delete(“key”);
localRedisTemplate.opsForValue().set(“key”, “value”, 100, TimeUnit.MILLISECONDS);
String ans = localRedisTemplate.opsForValue().get(“key”);
System.out.println(“value”.equals(ans));
TimeUnit.MILLISECONDS.sleep(200);
ans = localRedisTemplate.opsForValue().get(“key”);
System.out.println(“value”.equals(ans) + ” >> false ans should be null! ans=[” + ans + “]”);

defaultRedisTemplate.opsForValue().set(“key”, “value”, 100, TimeUnit.MILLISECONDS);
ans = defaultRedisTemplate.opsForValue().get(“key”);
System.out.println(ans);
}

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
上面的代码执行演示如下

上面的演示为动图,抓一下重点:

注意 localRedisTemplate, defaultRedisTemplate 两个对象不相同(看 debug 窗口后面的 @xxx)
同样两个 RedisTemplate 的 ConnectionFactory 也是两个不同的实例(即分别对应前面配置类中的两个 Factory)

执行后输出的结果正如我们预期的 redis 操作

塞值,马上取出没问题
失效后,再查询,返回 null

最后输出异常日志,提示如下

Description:

Parameter 0 of method redisTemplate in org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration required a single bean, but 2 were found:
– defaultLettuceConnectionFactory: defined by method ‘defaultLettuceConnectionFactory’ in class path resource [com/git/hui/boot/redis/config/RedisAutoConfig.class]
– localLettuceConnectionFactory: defined by method ‘localLettuceConnectionFactory’ in class path resource [com/git/hui/boot/redis/config/RedisAutoConfig.class]

Action:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
上面表示说有多个 ConnectionFactory 存在,然后创建默认的 RedisTemplate 就不知道该选择哪一个了,有两种方法
方法一:指定默认的 ConnectionFactory
借助 @Primary 来指定默认的连接工厂,然后在使用工程的时候,通过 @Qualifier 注解来显示指定,我需要的工厂是哪个(主要是 localRedisTemplate 这个 bean 的定义,如果不加,则会根据 defaultLettuceConnectionFactory 这个实例来创建 Redis 连接了)
@Bean
@Primary
public LettuceConnectionFactory defaultLettuceConnectionFactory(RedisStandaloneConfiguration defaultRedisConfig,
GenericObjectPoolConfig defaultPoolConfig) {
// …
}

@Bean
public RedisTemplate<String, String> defaultRedisTemplate(
@Qualifier(“defaultLettuceConnectionFactory”) LettuceConnectionFactory defaultLettuceConnectionFactory) {
// ….
}

@Bean
@ConditionalOnBean(name = “localRedisConfig”)
public LettuceConnectionFactory localLettuceConnectionFactory(RedisStandaloneConfiguration localRedisConfig,
GenericObjectPoolConfig localPoolConfig) {
// …
}

@Bean
@ConditionalOnBean(name = “localLettuceConnectionFactory”)
public RedisTemplate<String, String> localRedisTemplate(
@Qualifier(“localLettuceConnectionFactory”) LettuceConnectionFactory localLettuceConnectionFactory) {
// …
}
方法二:忽略默认的自动配置类
既然提示的是 org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration 类加载 bean 冲突,那么就不加载这个配置即可
@SpringBootApplication
@EnableAutoConfiguration(exclude = {RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class})
public class Application {
// …
}
II. 其他
0. 项目

工程:spring-boot-demo

module: 120-redis-config

1. 一灰灰 Blog

一灰灰 Blog 个人博客 https://blog.hhui.top

一灰灰 Blog-Spring 专题博客 http://spring.hhui.top

一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
2. 声明
尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现 bug 或者有更好的建议,欢迎批评指正,不吝感激

微博地址: 小灰灰 Blog

QQ:一灰灰 /3302797840

3. 扫描关注
一灰灰 blog

知识星球

退出移动版