迁移到SpringBoot 04 - Redis

相比于Spring来说,在SpringBoot中使用Redis大幅简化了。通过使用spring-boot-starter-data-redis,使用Redis变得非常简单。

基本步骤如下:

  1. 添加依赖
1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  1. 配置application.properties/yaml
1
2
3
4
5
6
7
spring:
redis:
host: 192.168.2.230
port: 6379
password: xxxxxx
database: 1
timeout: 3000ms
  1. 注入RedisTemplate使用
1
2
@Autowired
StringRedisTemplate stringRedisTemplate;

就是这么简单。

1. Redis自动注册

刚开始使用spring-boot-starter-data-redis的时候很奇怪在propertySource中的配置参数(spring.redis.*)是怎么起作用的?

最初怀疑是在包spring-boot-starter-data-redis中,但是查看源码发现这个包没有任何源码,只是一个pom文件,提供了对:spring-data-redis、jedis的依赖。

后来有怀疑是不是在spring-data-redis包中。上Github中看源码也没有。

最后才发现原来是在Spring-boot中的spring-boot-autoconfigure这个包里面的RedisAutoConfiguration这个类中。

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
@Configuration
@ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class })
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfiguration {
/**
* Redis connection configuration.
*/
@Configuration
@ConditionalOnClass(GenericObjectPool.class)
protected static class RedisConnectionConfiguration { private final RedisProperties properties;
public RedisConnectionConfiguration(RedisProperties properties,
ObjectProvider<RedisSentinelConfiguration> sentinelConfiguration,
ObjectProvider<RedisClusterConfiguration> clusterConfiguration) {
this.properties = properties;
this.sentinelConfiguration = sentinelConfiguration.getIfAvailable();
this.clusterConfiguration = clusterConfiguration.getIfAvailable();
}

@Bean
@ConditionalOnMissingBean(RedisConnectionFactory.class)
public JedisConnectionFactory redisConnectionFactory()
throws UnknownHostException {
return applyProperties(createJedisConnectionFactory());
}

// 根据参数情况决定创建那种类型的Factory:可以是Cluster、Sentinel或者普通模式。
private JedisConnectionFactory createJedisConnectionFactory() {
JedisPoolConfig poolConfig = this.properties.getPool() != null
? jedisPoolConfig() : new JedisPoolConfig();

if (getSentinelConfig() != null) {
return new JedisConnectionFactory(getSentinelConfig(), poolConfig);
}
if (getClusterConfiguration() != null) {
return new JedisConnectionFactory(getClusterConfiguration(), poolConfig);
}
return new JedisConnectionFactory(poolConfig);
}
...
}
....
}

可以看到在AutoConfiguration中大量使用了Condition类型的注解。spring-boot会根据当前类路径上存在的类情况以及Bean是否已经创建的情况决定是否要创建Bean。

上面只是代码的一部分,展示了怎么根据配置创建RedisConnectionFactory对象。

真正与PropertySource有关的代码在RedisProperties这个类中:

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* Configuration properties for Redis.
*
* @author Dave Syer
* @author Christoph Strobl
* @author Eddú Meléndez
* @author Marco Aust
*/
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
private int database = 0;
private String url;
....

看代码,通过@ConfigurationProperties这个注解指定了prefix,从而可以从.properties或.yaml类型的配置文件直接读取redis相关的配置参数。

2. 自定义Bean

RedisAutoConfiguration中会自动根据参数配置情况决定创建那种redis的链接池。这一点非常方便。可以直接在其他类中使用@Autowired注入:JedisConnectionFactory类型的变量。另外,该类还会自动创建两个Bean:

  • RedisTemplate
  • StringRedisTemplate
    但是通常情况下这两个Bean不一定能够满足要求(例如其序列化支持方式可能不满足要求),这时可以手动创建者类Bean。像这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Configuration
public class RedisConfig {

@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Autowired
RedisConnectionFactory redisConnectionFactory;

@Bean(name="redisSerializer")
public StringRedisSerializer redisSerializer() {
return new StringRedisSerializer();
}

@Bean(name="redisTemplate")
public RedisTemplate<String, String> redisTemplate() {
RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setDefaultSerializer(redisSerializer());
return redisTemplate;
}
}

你可以自己定义Serializer,达到完全的控制。上面只是个例子,实际调用的还是spring-data-redis中的StringRedisSerializer。

3. 关闭自动注册

当然,如果不需要Spring Boot自动注册这些Bean,可以禁用Redis的AutoConfiguration。比较常见的方式是通过@EnableAutoConfiguration注解中的exclude参数来解决,例如:

1
@EnableAutoConfiguration(exclude = {RedisAutoConfiguration.class})

更多方法可以参考附录。关闭自动注册以后就可以像以前一样自定义所有的Bean。

4. Intellij报错的问题

RedisAutoConfiguration会自动创建RedisConnectionFactory和RedisTemplate,但是在intellij idea中检测会有问题。只有当@Autowired写到Application类中的时候才不报错。添加到其他@Configuration类中则会报无法autowire错误:

Could not autowire bean 'RedisConnectionFactory'....

实际编译的时候不报错,说明是正确的,只是IDE检测的问题。这应该是idea的bug,或者支持还不完善。可以参考附录中的资料。

可以通过注解@SuppressWarnings这个注解解决这个问题,就如同上面的代码中显示的那样。

附录、参考资料

热评文章