前言
springboot集成redis只需要看懂RedisAutoConfiguration类即可!
pom依赖
<parent> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-parentartifactId> <version>1.5.9.RELEASEversion>parent><dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-data-redisartifactId>dependency>
下面简单解析下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.*/@Configurationprotected static class RedisConfiguration { // 如果容器中没有redisTemplate则创建一个该实例对象 // 我们在使用的时候需要进行增强,所以只用我们直接生成一个redisTemplate的bean,此处则不会生效 @Bean @ConditionalOnMissingBean(name = "redisTemplate") public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)throws UnknownHostException { RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>(); template.setConnectionFactory(redisConnectionFactory); return template; } // 如果容器中没有StringRedisTemplate则创建一个该实例对象 @Bean @ConditionalOnMissingBean(StringRedisTemplate.class) public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)throws UnknownHostException { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; }}}
这个类非常容易看懂,所以实际上集成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会自动失效):
@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory){ RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory); // 使用Jackson2JsonRedisSerialize 替换默认序列化(默认采用的是JDK序列化) Jackson2JsonRedisSerializer<Object> 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结束,如有疑问,欢迎留言讨论.
欢迎关注个人订阅号:Java技术宝典 ,及时获取最新分享.