springboot集成redis只需要看懂RedisAutoConfiguration类即可!
-----------------------------------惯例先上pom start-----------------------------------
org.springframework.boot
spring-boot-starter-parent
1.5.9.RELEASE
org.springframework.boot
spring-boot-starter-data-redis
----------------------------------- end -----------------------------------
下面简单解析下RedisAutoConfiguration类源码:
从类上面的注解可以看出spring自动装配redis是基于Jedis客户端实现.
@EnableConfigurationProperties(RedisProperties.class)指明了自动装配需要的配置,其中包含了单实例、哨兵模式、分片模式的配置,可以按需灵活使用.
@Configuration
//自动装配依赖条件
@ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class }
//启用RedisProperties配置类,注意该注解的目的是将使用@Configuration注解的类交给spring容器管理
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfiguration {
/**
* redis连接配置
* Redis connection configuration.
*/
@Configuration
@ConditionalOnClass(GenericObjectPool.class)
protected static class RedisConnectionConfiguration {
//基础配置
private final RedisProperties properties;
//哨兵配置
private final RedisSentinelConfiguration sentinelConfiguration;
//分片配置
private final RedisClusterConfiguration clusterConfiguration;
//构造注入配置文件
public RedisConnectionConfiguration(RedisProperties properties,
ObjectProvider sentinelConfiguration,
ObjectProvider clusterConfiguration) {
this.properties = properties;
this.sentinelConfiguration = sentinelConfiguration.getIfAvailable();
this.clusterConfiguration = clusterConfiguration.getIfAvailable();
}
//如果没有RedisConnectionFactory的实例则初始化一个redis工厂实例
@Bean
@ConditionalOnMissingBean(RedisConnectionFactory.class)
public JedisConnectionFactory redisConnectionFactory()
throws UnknownHostException {
return applyProperties(createJedisConnectionFactory());
}
//配置连接工厂的连接属性
protected final JedisConnectionFactory applyProperties(
JedisConnectionFactory factory) {
configureConnection(factory);
if (this.properties.isSsl()) {
factory.setUseSsl(true);
}
factory.setDatabase(this.properties.getDatabase());
if (this.properties.getTimeout() > 0) {
factory.setTimeout(this.properties.getTimeout());
}
return factory;
}
private void configureConnection(JedisConnectionFactory factory) {
if (StringUtils.hasText(this.properties.getUrl())) {
configureConnectionFromUrl(factory);
}
else {
factory.setHostName(this.properties.getHost());
factory.setPort(this.properties.getPort());
if (this.properties.getPassword() != null) {
factory.setPassword(this.properties.getPassword());
}
}
}
private void configureConnectionFromUrl(JedisConnectionFactory factory) {
String url = this.properties.getUrl();
if (url.startsWith("rediss://")) {
factory.setUseSsl(true);
}
try {
URI uri = new URI(url);
factory.setHostName(uri.getHost());
factory.setPort(uri.getPort());
if (uri.getUserInfo() != null) {
String password = uri.getUserInfo();
int index = password.lastIndexOf(":");
if (index >= 0) {
password = password.substring(index + 1);
}
factory.setPassword(password);
}
}
catch (URISyntaxException ex) {
throw new IllegalArgumentException("Malformed 'spring.redis.url' " + url,
ex);
}
}
protected final RedisSentinelConfiguration getSentinelConfig() {
if (this.sentinelConfiguration != null) {
return this.sentinelConfiguration;
}
Sentinel sentinelProperties = this.properties.getSentinel();
if (sentinelProperties != null) {
RedisSentinelConfiguration config = new RedisSentinelConfiguration();
config.master(sentinelProperties.getMaster());
config.setSentinels(createSentinels(sentinelProperties));
return config;
}
return null;
}
/**
* Create a {@link RedisClusterConfiguration} if necessary.
* @return {@literal null} if no cluster settings are set.
*/
protected final RedisClusterConfiguration getClusterConfiguration() {
if (this.clusterConfiguration != null) {
return this.clusterConfiguration;
}
if (this.properties.getCluster() == null) {
return null;
}
Cluster clusterProperties = this.properties.getCluster();
RedisClusterConfiguration config = new RedisClusterConfiguration(
clusterProperties.getNodes());
if (clusterProperties.getMaxRedirects() != null) {
config.setMaxRedirects(clusterProperties.getMaxRedirects());
}
return config;
}
//哨兵节点配置
private List createSentinels(Sentinel sentinel) {
List nodes = new ArrayList();
for (String node : StringUtils
.commaDelimitedListToStringArray(sentinel.getNodes())) {
try {
String[] parts = StringUtils.split(node, ":");
Assert.state(parts.length == 2, "Must be defined as 'host:port'");
nodes.add(new RedisNode(parts[0], Integer.valueOf(parts[1])));
}
catch (RuntimeException ex) {
throw new IllegalStateException(
"Invalid redis sentinel " + "property '" + node + "'", ex);
}
}
return nodes;
}
//创建连接工厂
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);
}
private JedisPoolConfig jedisPoolConfig() {
JedisPoolConfig config = new JedisPoolConfig();
RedisProperties.Pool props = this.properties.getPool();
config.setMaxTotal(props.getMaxActive());
config.setMaxIdle(props.getMaxIdle());
config.setMinIdle(props.getMinIdle());
config.setMaxWaitMillis(props.getMaxWait());
return config;
}
}
/**
* Standard Redis configuration.
*/
@Configuration
protected static class RedisConfiguration {
//如果容器中没有redisTemplate
这个类非常容易看懂,所以实际上集成redis就变得非常简单了,下面来看看具体项目使用配置:
先看下yml配置文件,配置非常清晰,使用哪种模式按指定配置即可
spring:
redis:
#host: 127.0.0.1 #单实例在此配置ip,配置单实例必须屏蔽cluster max-redirects 与 nodes
#port: 6379 #单实例在此配置端口
password:
timeout: 20000
pool:
max-active: 8 # 连接池最大连接数(使用负值表示没有限制)
min-idle: 0 #最小空闲连接:连接池中容许保持空闲状态的最小连接数量,低于这个数量将创建新的连接
max-idle: 8 #最大空闲连接:连接池中容许保持空闲状态的最大连接数量,超过的空闲连接将被释放
max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
sentinel: #哨兵模式 适用于读多写少
master: #配置主节点
nodes: #配置从节点
cluster: #集群在此配置节点,配置集群必须屏蔽host与port配置
max-redirects: 6 #最大的要重定向的次数(由于集群中数据存储在多个节点所以,在访问数据时需要通过节点进行转发)
nodes: 192.168.210.68:6379,192.168.210.68:6380,192.168.210.68:6381,... #分片至少要6个节点才能使用
再来看下在代码中使用
只用注入org.springframework.data.redis.core.RedisTemplate即可通过redisTemplate操作redis
另外由于redisTempate会将数据序列化后存储,而序列化默认使用JdkSerializationRedisSerializer,下面简单介绍下spring-data-redis的几个序列化类:
FastJson2JsonRedisSerializer: 序列化object对象为json字符串,存储的value值是带有双引号的,不利于反序列化
GenericToStringSerializer: 将任何对象toString()后再序列化
JacksonJsonRedisSerializer: 序列化object对象为json字符串,具备易读性
Jackson2JsonRedisSerializer: 同JacksonJsonRedisSerializer,推荐使用
JdkSerializationRedisSerializer: 序列化java对象(即只有实现了Serializable接口的对象才能被序列化),redis中存储的值不可读
StringRedisSerializer: 用于序列化字符串,不适用于对象
对比后存储key统一使用StringRedisSerializer,存储value统一使用Jackson2JsonRedisSerialize最为方便,下面即是对redisTemplate进行增强(注入新的redisTemplate,spring自动注入的redisTemplate会自动失效):
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory){
RedisTemplate template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 使用Jackson2JsonRedisSerialize 替换默认序列化(默认采用的是JDK序列化)
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
//序列化对象互转对象设置
ObjectMapper om = new ObjectMapper();
//设置任何对象的任何信息都可见
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//对所有非final类型的元素进行序列化
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
//设置redis存储value序列化方式
template.setValueSerializer(jackson2JsonRedisSerializer);
//设置redis存储key序列化方式
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
//调用此方法对上面设置的信息进行初始化
template.afterPropertiesSet();
return template;
}
至此,springboot1.5.9集成redis结束,如有疑问,欢迎留言讨论.