前言

RedisTemplate客户端是spring对底层依赖Jedis、Lettuce的高度封装,在Springboot1.X版本默认使用Jedis进行自动装配,在Springboot2.X版本默认使用Lettuce进行自动装配。

1.依赖

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.序列化

2.1 序列化对象

RedisTemplate客户端在存取数据时,并不需要像Jedis、Lettuce那样通过硬代码手动序列化(比如json、java serialization等),spring提供了多种序列化对象,然后通过代码配置的方式制定序列化器:

  • GenericToStringSerializer(可以将任何对象泛化为字符串并序列化)
  • JacksonJsonRedisSerializer(序列化object对象为json字符串)
  • Jackson2JsonRedisSerializer(和JacksonJsonRedisSerializer一样)
  • JdkSerializationRedisSerializer(序列化java对象,需要实现Serializable接口)
  • StringRedisSerializer(简单的字符串序列化)

2.2 性能对比

JdkSerializationRedisSerializer属于JDK原生序列化对象,效率自然是最快的,缺点是序列化后的结果字符串最长,也就意味着占用内存相对多点。Jackson2JsonRedisSerializer是将数据转化为json字符串,需要解析结构因此最慢,但生成的字符串结果较为紧凑。

3.配置文件

由于Redis依赖基于springboot的自动装配,所以只需要配置文件参数即可。

3.1 单机版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# redis数据库索引
spring.redis.database=0

# redis服务器IP
spring.redis.host=127.0.0.1

# redis服务器端口
spring.redis.port=6379

# redis服务器密码
spring.redis.password=abcdef

#连接池最大连接数(使用负值表示没有限制)
jedis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
jedis.pool.max-wait=-1
# 连接池中的最大空闲连接
jedis.pool.max-idle=8
# 连接池中的最小空闲连接
jedis.pool.min-idle=8
# 连接超时时间(毫秒)
jedis.pool.timeout=10000

3.2 主从版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# redis数据库索引
spring.redis.database=0

# redis服务器IP
spring.redis.host=127.0.0.1

# redis服务器端口
spring.redis.port=6379

# redis服务器密码
spring.redis.password=abcdef

#连接池最大连接数(使用负值表示没有限制)
jedis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
jedis.pool.max-wait=-1
# 连接池中的最大空闲连接
jedis.pool.max-idle=8
# 连接池中的最小空闲连接
jedis.pool.min-idle=8
# 连接超时时间(毫秒)
jedis.pool.timeout=10000

3.3 哨兵版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# redis数据库索引
spring.redis.database=0

# redis服务器IP
spring.redis.host=127.0.0.1

# redis服务器端口
spring.redis.port=6379

# redis服务器密码
spring.redis.password=abcdef

#连接池最大连接数(使用负值表示没有限制)
jedis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
jedis.pool.max-wait=-1
# 连接池中的最大空闲连接
jedis.pool.max-idle=8
# 连接池中的最小空闲连接
jedis.pool.min-idle=8
# 连接超时时间(毫秒)
jedis.pool.timeout=10000

3.4 集群版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# redis数据库索引
spring.redis.database=0

# redis集群节点
spring.redis.cluster.nodes=175.24.30.43:7000,175.24.30.43:7001,175.24.30.43:7002

# 最大重定向次数(默认5)
spring.redis.cluster.max-redirects=3

# redis服务器密码
spring.redis.password=paxos1990..

# 连接池最大连接数(默认8)
spring.redis.jedis.pool.max-active=8

# 连接池最大空闲连接(默认8)
spring.redis.jedis.pool.max-idle=8

# 连接池的最小空闲连接(默认0)
spring.redis.jedis.pool.min-idle=0

# 连接池最大阻塞等待时间(默认-1,表示没有限制)
spring.redis.jedis.pool.max-wait=-1

4.客户端对象

4.1 StringRedisTemplate

如果你对redis的操作仅涉及到字符串类型,那么直接使用Spring提供的StringRedisTemplate类即可,此类内部使用StringRedisSerializer序列化,代码方面直接注入:

1
2
@Autowired
public StringRedisTemplate stringRedisTemplate;

4.2 自定义RedisTemplate

通常的项目中不可能只用Redis来存储字符串,也不可能把所有对象一股脑转成Json字符串存储,因此需要额外注入一个RedisTemplate用于对象的存储,并且可以针对不同的数据结构设置不同的序列化规则,配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
@Configuration
public class RedisConfig {

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {

RedisTemplate<String, Object> template = new RedisTemplate();
template.setConnectionFactory(factory);

Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);

StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);

// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);

// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);

// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);

template.afterPropertiesSet();
return template;
}

/**
* 对hash类型的数据操作
*
* @param redisTemplate
* @return hash操作对象
*/
@Bean
public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForHash();
}

/**
* 对redis字符串类型数据操作
*
* @param redisTemplate
* @return 字符串操作对象
*/
@Bean
public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForValue();
}

/**
* 对链表类型的数据操作
*
* @param redisTemplate
* @return list操作对象
*/
@Bean
public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForList();
}

/**
* 对无序集合类型的数据操作
*
* @param redisTemplate
* @return set操作对象
*/
@Bean
public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForSet();
}

/**
* 对有序集合类型的数据操作
*
* @param redisTemplate
* @return zset操作对象
*/
@Bean
public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForZSet();
}
}

5.Springboot自动装配

5.1 自动装配类

图片

从RedisTemplate的自动装配类可以看出来,Springboot会自动向IOC注入RedisTemplate、StringRedisTemplate俩个类,但都是有前提条件且注入的操作都比较粗糙,很多属性都没有设置,所以这俩个类的注入只会在你没有手动注入的情况下生效。

另外RedisTemplate底层依赖Lettuce或Jedis,至于使用哪个完全依赖配置方法中的参数RedisConnectionFactory,这个类有LettuceConnectionConfigurationJedisConnectionConfiguration俩个实现类,分别对应Lettuce和Jedis俩个客户端。

5.2 默认底层依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* Lettuce客户端 连接配置类
*/
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({RedisClient.class})
class LettuceConnectionConfiguration extends RedisConnectionConfiguration {

@Bean
@ConditionalOnMissingBean({RedisConnectionFactory.class})
LettuceConnectionFactory redisConnectionFactory(ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers, ClientResources clientResources) throws UnknownHostException {
LettuceClientConfiguration clientConfig = this.getLettuceClientConfiguration(builderCustomizers, clientResources, this.getProperties().getLettuce().getPool());
return this.createLettuceConnectionFactory(clientConfig);
}

// 其他省略...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* Jedis客户端 连接配置类
*/
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({GenericObjectPool.class, JedisConnection.class, Jedis.class})
class JedisConnectionConfiguration extends RedisConnectionConfiguration {

@Bean
@ConditionalOnMissingBean({RedisConnectionFactory.class})
JedisConnectionFactory redisConnectionFactory(ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) throws UnknownHostException {
return this.createJedisConnectionFactory(builderCustomizers);
}

// 其他省略...
}

从代码可以看出,Springboot会将这俩个客户端的配置类都尝试注册IOC(包括包含的RedisConnectionFactory),但是在Springboot2.X版本里默认只包含Lettuce的依赖,所以在@ConditionalOnClass的注入限制条件下,默认使用的是Lettuce客户端。

5.3 Springboot2.X使用Jedis

如果想要在Springboot2.X的RedisTemplate使用Jedis客户端实现,就需要对依赖进行处理,排除包含的Lettuce依赖,再添加Jedis依赖。这样Lettuce注入时,就无法满足@ConditionalOnClass的条件,而Jedis正好满足。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<!-- 排除lettuce依赖 -->
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>

注:Springboot1.X版本仅支持Jedis底层依赖,有兴趣可以自己看源码。

评论