Polish "Add Lettuce Redis driver autoconfiguration"

Closes gh-5311
This commit is contained in:
Stephane Nicoll 2017-05-02 15:16:11 +02:00
parent 4563da9ac7
commit e7efa8f133
14 changed files with 733 additions and 749 deletions

View File

@ -244,11 +244,6 @@
<artifactId>jedis</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>

View File

@ -100,6 +100,11 @@
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.projectreactor.ipc</groupId>
<artifactId>reactor-netty</artifactId>
@ -481,11 +486,6 @@
<artifactId>jedis</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>

View File

@ -0,0 +1,120 @@
/*
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.data.redis;
import java.net.UnknownHostException;
import org.apache.commons.pool2.impl.GenericObjectPool;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnection;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.util.StringUtils;
/**
* Redis connection configuration using Jedis.
*
* @author Mark Paluch
* @author Stephane Nicoll
*/
@Configuration
@ConditionalOnClass({ GenericObjectPool.class, JedisConnection.class, Jedis.class })
class JedisConnectionConfiguration extends RedisConnectionConfiguration {
private final RedisProperties properties;
JedisConnectionConfiguration(RedisProperties properties,
ObjectProvider<RedisSentinelConfiguration> sentinelConfiguration,
ObjectProvider<RedisClusterConfiguration> clusterConfiguration) {
super(properties, sentinelConfiguration, clusterConfiguration);
this.properties = properties;
}
@Bean
@ConditionalOnMissingBean(RedisConnectionFactory.class)
public JedisConnectionFactory redisConnectionFactory() throws UnknownHostException {
return applyProperties(createJedisConnectionFactory());
}
private 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) {
ConnectionInfo connectionInfo = parseUrl(this.properties.getUrl());
factory.setUseSsl(connectionInfo.isUseSsl());
factory.setHostName(connectionInfo.getHostName());
factory.setPort(connectionInfo.getPort());
if (connectionInfo.getPassword() != null) {
factory.setPassword(connectionInfo.getPassword());
}
}
private JedisConnectionFactory createJedisConnectionFactory() {
RedisProperties.Pool pool = this.properties.getJedis().getPool();
JedisPoolConfig poolConfig = pool != null
? jedisPoolConfig(pool) : 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(RedisProperties.Pool pool) {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(pool.getMaxActive());
config.setMaxIdle(pool.getMaxIdle());
config.setMinIdle(pool.getMinIdle());
config.setMaxWaitMillis(pool.getMaxWait());
return config;
}
}

View File

@ -0,0 +1,197 @@
/*
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.data.redis;
import java.net.UnknownHostException;
import io.lettuce.core.RedisClient;
import io.lettuce.core.cluster.RedisClusterClient;
import io.lettuce.core.resource.ClientResources;
import io.lettuce.core.resource.DefaultClientResources;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.lettuce.DefaultLettucePool;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.util.StringUtils;
/**
* Redis connection configuration using Lettuce.
*
* @author Mark Paluch
*/
@Configuration
@ConditionalOnClass({ GenericObjectPool.class, RedisClient.class, RedisClusterClient.class })
class LettuceConnectionConfiguration extends RedisConnectionConfiguration {
private final RedisProperties properties;
LettuceConnectionConfiguration(RedisProperties properties,
ObjectProvider<RedisSentinelConfiguration> sentinelConfigurationProvider,
ObjectProvider<RedisClusterConfiguration> clusterConfigurationProvider) {
super(properties, sentinelConfigurationProvider, clusterConfigurationProvider);
this.properties = properties;
}
@Bean(destroyMethod = "shutdown")
@ConditionalOnMissingBean(ClientResources.class)
public DefaultClientResources lettuceClientResources() {
return DefaultClientResources.create();
}
@Bean
@ConditionalOnMissingBean(RedisConnectionFactory.class)
public LettuceConnectionFactory redisConnectionFactory(
ClientResources clientResources) throws UnknownHostException {
return applyProperties(createLettuceConnectionFactory(clientResources));
}
private LettuceConnectionFactory applyProperties(LettuceConnectionFactory factory) {
configureConnection(factory);
if (this.properties.isSsl()) {
factory.setUseSsl(true);
}
if (this.properties.getLettuce() != null) {
RedisProperties.Lettuce lettuce = this.properties.getLettuce();
if (lettuce.getShutdownTimeout() >= 0) {
factory.setShutdownTimeout(
this.properties.getLettuce().getShutdownTimeout());
}
}
return factory;
}
private void configureConnection(LettuceConnectionFactory 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());
}
factory.setDatabase(this.properties.getDatabase());
if (this.properties.getTimeout() > 0) {
factory.setTimeout(this.properties.getTimeout());
}
}
}
private void configureConnectionFromUrl(LettuceConnectionFactory factory) {
ConnectionInfo connectionInfo = parseUrl(this.properties.getUrl());
factory.setUseSsl(connectionInfo.isUseSsl());
factory.setHostName(connectionInfo.getHostName());
factory.setPort(connectionInfo.getPort());
if (connectionInfo.getPassword() != null) {
factory.setPassword(connectionInfo.getPassword());
}
}
private DefaultLettucePool applyProperties(DefaultLettucePool pool) {
if (StringUtils.hasText(this.properties.getUrl())) {
configureConnectionFromUrl(pool);
}
else {
pool.setHostName(this.properties.getHost());
pool.setPort(this.properties.getPort());
if (this.properties.getPassword() != null) {
pool.setPassword(this.properties.getPassword());
}
pool.setDatabase(this.properties.getDatabase());
}
if (this.properties.getTimeout() > 0) {
pool.setTimeout(this.properties.getTimeout());
}
pool.afterPropertiesSet();
return pool;
}
private void configureConnectionFromUrl(DefaultLettucePool lettucePool) {
ConnectionInfo connectionInfo = parseUrl(this.properties.getUrl());
lettucePool.setHostName(connectionInfo.getHostName());
lettucePool.setPort(connectionInfo.getPort());
if (connectionInfo.getPassword() != null) {
lettucePool.setPassword(connectionInfo.getPassword());
}
}
private LettuceConnectionFactory createLettuceConnectionFactory(
ClientResources clientResources) {
if (getSentinelConfig() != null) {
if (this.properties.getLettuce() != null
&& this.properties.getLettuce().getPool() != null) {
DefaultLettucePool lettucePool = new DefaultLettucePool(
getSentinelConfig());
return new LettuceConnectionFactory(applyProperties(
applyClientResources(lettucePool, clientResources)));
}
return applyClientResources(
new LettuceConnectionFactory(getSentinelConfig()),
clientResources);
}
if (getClusterConfiguration() != null) {
return applyClientResources(
new LettuceConnectionFactory(getClusterConfiguration()),
clientResources);
}
if (this.properties.getLettuce() != null
&& this.properties.getLettuce().getPool() != null) {
GenericObjectPoolConfig config = lettucePoolConfig(
this.properties.getLettuce().getPool());
DefaultLettucePool lettucePool = new DefaultLettucePool(
this.properties.getHost(), this.properties.getPort(), config);
return new LettuceConnectionFactory(applyProperties(
applyClientResources(lettucePool, clientResources)));
}
return applyClientResources(new LettuceConnectionFactory(), clientResources);
}
private DefaultLettucePool applyClientResources(DefaultLettucePool lettucePool,
ClientResources clientResources) {
lettucePool.setClientResources(clientResources);
return lettucePool;
}
private LettuceConnectionFactory applyClientResources(
LettuceConnectionFactory factory, ClientResources clientResources) {
factory.setClientResources(clientResources);
return factory;
}
private GenericObjectPoolConfig lettucePoolConfig(RedisProperties.Pool props) {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMaxTotal(props.getMaxActive());
config.setMaxIdle(props.getMaxIdle());
config.setMinIdle(props.getMinIdle());
config.setMaxWaitMillis(props.getMaxWait());
return config;
}
}

View File

@ -16,44 +16,19 @@
package org.springframework.boot.autoconfigure.data.redis;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import io.lettuce.core.RedisClient;
import io.lettuce.core.cluster.RedisClusterClient;
import io.lettuce.core.resource.ClientResources;
import io.lettuce.core.resource.DefaultClientResources;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties.Cluster;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties.Lettuce;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties.Sentinel;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.context.annotation.Import;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnection;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.DefaultLettucePool;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Redis support.
@ -71,393 +46,28 @@ import org.springframework.util.StringUtils;
@Configuration
@ConditionalOnClass({ RedisOperations.class })
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class,
JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
/**
* Jedis Redis connection configuration.
*/
@Configuration
@ConditionalOnClass({ GenericObjectPool.class, JedisConnection.class, Jedis.class })
protected static class JedisRedisConnectionConfiguration
extends RedisBaseConfiguration {
private final RedisProperties properties;
public JedisRedisConnectionConfiguration(RedisProperties properties,
ObjectProvider<RedisSentinelConfiguration> sentinelConfiguration,
ObjectProvider<RedisClusterConfiguration> clusterConfiguration) {
super(properties, sentinelConfiguration, clusterConfiguration);
this.properties = properties;
}
@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);
}
}
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;
}
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(
RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
/**
* Lettuce Redis connection configuration.
*/
@Configuration
@ConditionalOnClass({ GenericObjectPool.class, RedisClient.class,
RedisClusterClient.class })
protected static class LettuceRedisConnectionConfiguration
extends RedisBaseConfiguration {
private final RedisProperties properties;
public LettuceRedisConnectionConfiguration(RedisProperties properties,
ObjectProvider<RedisSentinelConfiguration> sentinelConfigurationProvider,
ObjectProvider<RedisClusterConfiguration> clusterConfigurationProvider) {
super(properties, sentinelConfigurationProvider,
clusterConfigurationProvider);
this.properties = properties;
}
@Bean(destroyMethod = "shutdown")
@ConditionalOnMissingBean(ClientResources.class)
public DefaultClientResources lettuceClientResources() {
return DefaultClientResources.create();
}
@Bean
@ConditionalOnMissingBean(RedisConnectionFactory.class)
public LettuceConnectionFactory redisConnectionFactory(
ClientResources clientResources) throws UnknownHostException {
return applyProperties(createLettuceConnectionFactory(clientResources));
}
protected final LettuceConnectionFactory applyProperties(
LettuceConnectionFactory factory) {
configureConnection(factory);
if (this.properties.isSsl()) {
factory.setUseSsl(true);
}
if (this.properties.getLettuce() != null) {
Lettuce lettuce = this.properties.getLettuce();
if (lettuce.getShutdownTimeout() >= 0) {
factory.setShutdownTimeout(
this.properties.getLettuce().getShutdownTimeout());
}
}
return factory;
}
private void configureConnection(LettuceConnectionFactory 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());
}
factory.setDatabase(this.properties.getDatabase());
if (this.properties.getTimeout() > 0) {
factory.setTimeout(this.properties.getTimeout());
}
}
}
private void configureConnectionFromUrl(LettuceConnectionFactory 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 DefaultLettucePool applyProperties(DefaultLettucePool pool) {
if (StringUtils.hasText(this.properties.getUrl())) {
configureConnectionFromUrl(pool);
}
else {
pool.setHostName(this.properties.getHost());
pool.setPort(this.properties.getPort());
if (this.properties.getPassword() != null) {
pool.setPassword(this.properties.getPassword());
}
pool.setDatabase(this.properties.getDatabase());
}
if (this.properties.getTimeout() > 0) {
pool.setTimeout(this.properties.getTimeout());
}
pool.afterPropertiesSet();
return pool;
}
private void configureConnectionFromUrl(DefaultLettucePool lettucePool) {
String url = this.properties.getUrl();
try {
URI uri = new URI(url);
lettucePool.setHostName(uri.getHost());
lettucePool.setPort(uri.getPort());
if (uri.getUserInfo() != null) {
String password = uri.getUserInfo();
int index = password.lastIndexOf(":");
if (index >= 0) {
password = password.substring(index + 1);
}
lettucePool.setPassword(password);
}
}
catch (URISyntaxException ex) {
throw new IllegalArgumentException("Malformed 'spring.redis.url' " + url,
ex);
}
}
private LettuceConnectionFactory createLettuceConnectionFactory(
ClientResources clientResources) {
if (getSentinelConfig() != null) {
if (this.properties.getLettuce() != null
&& this.properties.getLettuce().getPool() != null) {
DefaultLettucePool lettucePool = new DefaultLettucePool(
getSentinelConfig());
return new LettuceConnectionFactory(applyProperties(
applyClientResources(lettucePool, clientResources)));
}
return applyClientResources(
new LettuceConnectionFactory(getSentinelConfig()),
clientResources);
}
if (getClusterConfiguration() != null) {
return applyClientResources(
new LettuceConnectionFactory(getClusterConfiguration()),
clientResources);
}
if (this.properties.getLettuce() != null
&& this.properties.getLettuce().getPool() != null) {
GenericObjectPoolConfig config = lettucePoolConfig(
this.properties.getLettuce().getPool());
DefaultLettucePool lettucePool = new DefaultLettucePool(
this.properties.getHost(), this.properties.getPort(), config);
return new LettuceConnectionFactory(applyProperties(
applyClientResources(lettucePool, clientResources)));
}
return applyClientResources(new LettuceConnectionFactory(), clientResources);
}
private DefaultLettucePool applyClientResources(DefaultLettucePool lettucePool,
ClientResources clientResources) {
lettucePool.setClientResources(clientResources);
return lettucePool;
}
private LettuceConnectionFactory applyClientResources(
LettuceConnectionFactory factory, ClientResources clientResources) {
factory.setClientResources(clientResources);
return factory;
}
private GenericObjectPoolConfig lettucePoolConfig(RedisProperties.Pool props) {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMaxTotal(props.getMaxActive());
config.setMaxIdle(props.getMaxIdle());
config.setMinIdle(props.getMinIdle());
config.setMaxWaitMillis(props.getMaxWait());
return config;
}
}
protected abstract static class RedisBaseConfiguration {
private final RedisProperties properties;
private final RedisSentinelConfiguration sentinelConfiguration;
private final RedisClusterConfiguration clusterConfiguration;
protected RedisBaseConfiguration(RedisProperties properties,
ObjectProvider<RedisSentinelConfiguration> sentinelConfigurationProvider,
ObjectProvider<RedisClusterConfiguration> clusterConfigurationProvider) {
this.properties = properties;
this.sentinelConfiguration = sentinelConfigurationProvider.getIfAvailable();
this.clusterConfiguration = clusterConfigurationProvider.getIfAvailable();
}
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<RedisNode> createSentinels(Sentinel sentinel) {
List<RedisNode> 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;
}
}
/**
* Standard Redis configuration.
*/
@Configuration
protected static class RedisConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(
RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean(StringRedisTemplate.class)
public StringRedisTemplate stringRedisTemplate(
RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean(StringRedisTemplate.class)
public StringRedisTemplate stringRedisTemplate(
RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}

View File

@ -0,0 +1,153 @@
/*
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.data.redis;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Base Redis connection configuration.
*
* @author Mark Paluch
* @author Stephane Nicoll
*/
abstract class RedisConnectionConfiguration {
private final RedisProperties properties;
private final RedisSentinelConfiguration sentinelConfiguration;
private final RedisClusterConfiguration clusterConfiguration;
protected RedisConnectionConfiguration(RedisProperties properties,
ObjectProvider<RedisSentinelConfiguration> sentinelConfigurationProvider,
ObjectProvider<RedisClusterConfiguration> clusterConfigurationProvider) {
this.properties = properties;
this.sentinelConfiguration = sentinelConfigurationProvider.getIfAvailable();
this.clusterConfiguration = clusterConfigurationProvider.getIfAvailable();
}
protected final RedisSentinelConfiguration getSentinelConfig() {
if (this.sentinelConfiguration != null) {
return this.sentinelConfiguration;
}
RedisProperties.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;
}
RedisProperties.Cluster clusterProperties = this.properties.getCluster();
RedisClusterConfiguration config = new RedisClusterConfiguration(
clusterProperties.getNodes());
if (clusterProperties.getMaxRedirects() != null) {
config.setMaxRedirects(clusterProperties.getMaxRedirects());
}
return config;
}
private List<RedisNode> createSentinels(RedisProperties.Sentinel sentinel) {
List<RedisNode> 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;
}
protected ConnectionInfo parseUrl(String url) {
try {
URI uri = new URI(url);
boolean useSsl = (url.startsWith("rediss://"));
String password = null;
if (uri.getUserInfo() != null) {
password = uri.getUserInfo();
int index = password.lastIndexOf(":");
if (index >= 0) {
password = password.substring(index + 1);
}
}
return new ConnectionInfo(uri, useSsl, password);
}
catch (URISyntaxException ex) {
throw new IllegalArgumentException("Malformed url '" + url + "'", ex);
}
}
protected static class ConnectionInfo {
private final URI uri;
private final boolean useSsl;
private final String password;
public ConnectionInfo(URI uri, boolean useSsl, String password) {
this.uri = uri;
this.useSsl = useSsl;
this.password = password;
}
public boolean isUseSsl() {
return this.useSsl;
}
public String getHostName() {
return this.uri.getHost();
}
public int getPort() {
return this.uri.getPort();
}
public String getPassword() {
return this.password;
}
}
}

View File

@ -19,7 +19,6 @@ package org.springframework.boot.autoconfigure.data.redis;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
/**
* Configuration properties for Redis.
@ -29,6 +28,7 @@ import org.springframework.boot.context.properties.DeprecatedConfigurationProper
* @author Eddú Meléndez
* @author Marco Aust
* @author Mark Paluch
* @author Stephane Nicoll
*/
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
@ -68,21 +68,13 @@ public class RedisProperties {
*/
private int timeout;
private Pool pool;
private Sentinel sentinel;
private Cluster cluster;
/**
* Jedis client properties.
*/
private Jedis jedis;
private final Jedis jedis = new Jedis();
/**
* Lettuce client properties.
*/
private Lettuce lettuce;
private final Lettuce lettuce = new Lettuce();
public int getDatabase() {
return this.database;
@ -148,15 +140,6 @@ public class RedisProperties {
this.sentinel = sentinel;
}
@DeprecatedConfigurationProperty(reason = "Moved to client-specific properties", replacement = "spring.redis.jedis.pool")
public Pool getPool() {
return this.pool;
}
public void setPool(Pool pool) {
this.pool = pool;
}
public Cluster getCluster() {
return this.cluster;
}
@ -166,19 +149,11 @@ public class RedisProperties {
}
public Jedis getJedis() {
return jedis;
}
public void setJedis(Jedis jedis) {
this.jedis = jedis;
return this.jedis;
}
public Lettuce getLettuce() {
return lettuce;
}
public void setLettuce(Lettuce lettuce) {
this.lettuce = lettuce;
return this.lettuce;
}
/**
@ -339,7 +314,7 @@ public class RedisProperties {
public static class Lettuce {
/**
* Shutdown timeout in milliseconds for lettuce.
* Shutdown timeout in milliseconds.
*/
private int shutdownTimeout = 2000;

View File

@ -1,198 +0,0 @@
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.data.redis;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.StatefulRedisConnection;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.data.redis.connection.lettuce.DefaultLettucePool;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.StringUtils;
import static org.assertj.core.api.Assertions.*;
/**
* Tests for {@link RedisAutoConfiguration} using Lettuce as client.
*
* @author Mark Paluch
*/
public class LettuceRedisAutoConfigurationTests {
private AnnotationConfigApplicationContext context;
@Before
public void setup() {
this.context = new AnnotationConfigApplicationContext();
}
@After
public void close() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void testOverrideRedisConfiguration() throws Exception {
load("spring.redis.host:foo", "spring.redis.database:1");
assertThat(this.context.getBean(LettuceConnectionFactory.class).getHostName())
.isEqualTo("foo");
assertThat(this.context.getBean(LettuceConnectionFactory.class).getDatabase())
.isEqualTo(1);
}
@Test
public void testOverrideUrlRedisConfiguration() throws Exception {
load("spring.redis.host:foo", "spring.redis.password:xyz",
"spring.redis.port:1000", "spring.redis.ssl:true",
"spring.redis.url:redis://user:password@example:33");
assertThat(this.context.getBean(LettuceConnectionFactory.class).getHostName())
.isEqualTo("example");
assertThat(this.context.getBean(LettuceConnectionFactory.class).getPort())
.isEqualTo(33);
assertThat(this.context.getBean(LettuceConnectionFactory.class).getPassword())
.isEqualTo("password");
assertThat(this.context.getBean(LettuceConnectionFactory.class).isUseSsl())
.isEqualTo(true);
}
@Test
public void testSslRedisConfiguration() throws Exception {
load("spring.redis.host:foo", "spring.redis.ssl:true");
assertThat(this.context.getBean(LettuceConnectionFactory.class).getHostName())
.isEqualTo("foo");
assertThat(this.context.getBean(LettuceConnectionFactory.class).isUseSsl())
.isTrue();
}
@Test
public void testRedisConfigurationWithPool() throws Exception {
load("spring.redis.host:foo", "spring.redis.lettuce.pool.max-idle:1");
assertThat(this.context.getBean(LettuceConnectionFactory.class).getHostName())
.isEqualTo("foo");
assertThat(getDefaultLettucePool(
this.context.getBean(LettuceConnectionFactory.class)).getHostName())
.isEqualTo("foo");
assertThat(getDefaultLettucePool(
this.context.getBean(LettuceConnectionFactory.class)).getPoolConfig()
.getMaxIdle()).isEqualTo(1);
}
@Test
public void testRedisConfigurationWithTimeout() throws Exception {
load("spring.redis.host:foo", "spring.redis.timeout:100");
assertThat(this.context.getBean(LettuceConnectionFactory.class).getHostName())
.isEqualTo("foo");
assertThat(this.context.getBean(LettuceConnectionFactory.class).getTimeout())
.isEqualTo(100);
}
@Test
public void testRedisConfigurationWithSentinel() throws Exception {
List<String> sentinels = Arrays.asList("127.0.0.1:26379", "127.0.0.1:26380");
if (isAtLeastOneNodeAvailable(sentinels)) {
load("spring.redis.sentinel.master:mymaster", "spring.redis.sentinel.nodes:"
+ StringUtils.collectionToCommaDelimitedString(sentinels));
assertThat(this.context.getBean(LettuceConnectionFactory.class)
.isRedisSentinelAware()).isTrue();
}
}
@Test
public void testRedisConfigurationWithCluster() throws Exception {
List<String> clusterNodes = Arrays.asList("127.0.0.1:27379", "127.0.0.1:27380");
load("spring.redis.cluster.nodes[0]:" + clusterNodes.get(0),
"spring.redis.cluster.nodes[1]:" + clusterNodes.get(1));
assertThat(this.context.getBean(LettuceConnectionFactory.class)
.getClusterConnection()).isNotNull();
}
private DefaultLettucePool getDefaultLettucePool(LettuceConnectionFactory factory) {
return (DefaultLettucePool) ReflectionTestUtils.getField(factory, "pool");
}
private boolean isAtLeastOneNodeAvailable(List<String> nodes) {
for (String node : nodes) {
if (isAvailable(node)) {
return true;
}
}
return false;
}
private boolean isAvailable(String node) {
RedisClient redisClient = null;
try {
String[] hostAndPort = node.split(":");
redisClient = RedisClient.create(new RedisURI(hostAndPort[0],
Integer.valueOf(hostAndPort[1]), 10, TimeUnit.SECONDS));
StatefulRedisConnection<String, String> connection = redisClient.connect();
connection.sync().ping();
connection.close();
return true;
}
catch (Exception ex) {
return false;
}
finally {
if (redisClient != null) {
try {
redisClient.shutdown(0, 0, TimeUnit.SECONDS);
}
catch (Exception ex) {
// Continue
}
}
}
}
private void load(String... environment) {
this.context = doLoad(environment);
}
private AnnotationConfigApplicationContext doLoad(String... environment) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(applicationContext, environment);
applicationContext.register(
RedisAutoConfiguration.LettuceRedisConnectionConfiguration.class,
PropertyPlaceholderAutoConfiguration.class,
EnableRedisPropertiesConfiguration.class);
applicationContext.refresh();
return applicationContext;
}
@EnableConfigurationProperties(RedisProperties.class)
private static class EnableRedisPropertiesConfiguration {
}
}

View File

@ -0,0 +1,158 @@
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.data.redis;
import java.util.Arrays;
import java.util.List;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import redis.clients.jedis.Jedis;
import org.springframework.boot.junit.runner.classpath.ClassPathExclusions;
import org.springframework.boot.junit.runner.classpath.ModifiedClassPathRunner;
import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.util.StringUtils;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link RedisAutoConfiguration} when Lettuce is not on the classpath.
*
* @author Mark Paluch
* @author Stephane Nicoll
*/
@RunWith(ModifiedClassPathRunner.class)
@ClassPathExclusions("lettuce-core-*.jar")
public class RedisAutoConfigurationJedisTests {
private AnnotationConfigApplicationContext context;
@After
public void close() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void testOverrideRedisConfiguration() throws Exception {
load("spring.redis.host:foo", "spring.redis.database:1");
JedisConnectionFactory cf = this.context.getBean(JedisConnectionFactory.class);
assertThat(cf.getHostName()).isEqualTo("foo");
assertThat(cf.getDatabase()).isEqualTo(1);
assertThat(cf.getPassword()).isNull();
assertThat(cf.isUseSsl()).isFalse();
}
@Test
public void testOverrideUrlRedisConfiguration() throws Exception {
load("spring.redis.host:foo", "spring.redis.password:xyz",
"spring.redis.port:1000", "spring.redis.ssl:true",
"spring.redis.url:redis://user:password@example:33");
JedisConnectionFactory cf = this.context.getBean(JedisConnectionFactory.class);
assertThat(cf.getHostName()).isEqualTo("example");
assertThat(cf.getPort()).isEqualTo(33);
assertThat(cf.getPassword()).isEqualTo("password");
assertThat(cf.isUseSsl()).isTrue();
}
@Test
public void testRedisConfigurationWithPool() throws Exception {
load("spring.redis.host:foo", "spring.redis.jedis.pool.max-idle:1");
JedisConnectionFactory cf = this.context.getBean(JedisConnectionFactory.class);
assertThat(cf.getHostName()).isEqualTo("foo");
assertThat(cf.getPoolConfig().getMaxIdle()).isEqualTo(1);
}
@Test
public void testRedisConfigurationWithTimeout() throws Exception {
load("spring.redis.host:foo", "spring.redis.timeout:100");
JedisConnectionFactory cf = this.context.getBean(JedisConnectionFactory.class);
assertThat(cf.getHostName()).isEqualTo("foo");
assertThat(cf.getTimeout()).isEqualTo(100);
}
@Test
public void testRedisConfigurationWithSentinel() throws Exception {
List<String> sentinels = Arrays.asList("127.0.0.1:26379", "127.0.0.1:26380");
if (isAtLeastOneNodeAvailable(sentinels)) {
load("spring.redis.sentinel.master:mymaster", "spring.redis.sentinel.nodes:"
+ StringUtils.collectionToCommaDelimitedString(sentinels));
assertThat(this.context.getBean(JedisConnectionFactory.class)
.isRedisSentinelAware()).isTrue();
}
}
@Test
public void testRedisConfigurationWithCluster() throws Exception {
List<String> clusterNodes = Arrays.asList("127.0.0.1:27379", "127.0.0.1:27380");
if (isAtLeastOneNodeAvailable(clusterNodes)) {
load("spring.redis.cluster.nodes[0]:" + clusterNodes.get(0),
"spring.redis.cluster.nodes[1]:" + clusterNodes.get(1));
assertThat(this.context.getBean(JedisConnectionFactory.class)
.getClusterConnection()).isNotNull();
}
}
private void load(String... environment) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(ctx, environment);
ctx.register(RedisAutoConfiguration.class);
ctx.refresh();
this.context = ctx;
}
private boolean isAtLeastOneNodeAvailable(List<String> nodes) {
for (String node : nodes) {
if (isAvailable(node)) {
return true;
}
}
return false;
}
private boolean isAvailable(String node) {
Jedis jedis = null;
try {
String[] hostAndPort = node.split(":");
jedis = new Jedis(hostAndPort[0], Integer.valueOf(hostAndPort[1]));
jedis.connect();
jedis.ping();
return true;
}
catch (Exception ex) {
return false;
}
finally {
if (jedis != null) {
try {
jedis.disconnect();
jedis.close();
}
catch (Exception ex) {
// Continue
}
}
}
}
}

View File

@ -18,19 +18,21 @@ package org.springframework.boot.autoconfigure.data.redis;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.StatefulRedisConnection;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.DefaultLettucePool;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.StringUtils;
import static org.assertj.core.api.Assertions.assertThat;
@ -44,16 +46,12 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Eddú Meléndez
* @author Marco Aust
* @author Mark Paluch
* @author Stephane Nicoll
*/
public class RedisAutoConfigurationTests {
private AnnotationConfigApplicationContext context;
@Before
public void setup() {
this.context = new AnnotationConfigApplicationContext();
}
@After
public void close() {
if (this.context != null) {
@ -62,7 +60,7 @@ public class RedisAutoConfigurationTests {
}
@Test
public void testDefaultRedisConfiguration() throws Exception {
public void testDefaultRedisConfiguration() {
load();
assertThat(this.context.getBean("redisTemplate", RedisOperations.class))
.isNotNull();
@ -70,45 +68,42 @@ public class RedisAutoConfigurationTests {
}
@Test
public void testOverrideRedisConfiguration() throws Exception {
public void testOverrideRedisConfiguration() {
load("spring.redis.host:foo", "spring.redis.database:1");
assertThat(this.context.getBean(JedisConnectionFactory.class).getHostName())
.isEqualTo("foo");
assertThat(this.context.getBean(JedisConnectionFactory.class).getDatabase())
.isEqualTo(1);
LettuceConnectionFactory cf = this.context.getBean(LettuceConnectionFactory.class);
assertThat(cf.getHostName()).isEqualTo("foo");
assertThat(cf.getDatabase()).isEqualTo(1);
assertThat(cf.getPassword()).isNull();
assertThat(cf.isUseSsl()).isFalse();
}
@Test
public void testOverrideUrlRedisConfiguration() throws Exception {
public void testOverrideUrlRedisConfiguration() {
load("spring.redis.host:foo", "spring.redis.password:xyz",
"spring.redis.port:1000", "spring.redis.ssl:true",
"spring.redis.url:redis://user:password@example:33");
assertThat(this.context.getBean(JedisConnectionFactory.class).getHostName())
.isEqualTo("example");
assertThat(this.context.getBean(JedisConnectionFactory.class).getPort())
.isEqualTo(33);
assertThat(this.context.getBean(JedisConnectionFactory.class).getPassword())
.isEqualTo("password");
assertThat(this.context.getBean(JedisConnectionFactory.class).isUseSsl())
.isEqualTo(true);
LettuceConnectionFactory cf = this.context.getBean(LettuceConnectionFactory.class);
assertThat(cf.getHostName()).isEqualTo("example");
assertThat(cf.getPort()).isEqualTo(33);
assertThat(cf.getPassword()).isEqualTo("password");
assertThat(cf.isUseSsl()).isTrue();
}
@Test
public void testRedisConfigurationWithPool() throws Exception {
load("spring.redis.host:foo", "spring.redis.jedis.pool.max-idle:1");
assertThat(this.context.getBean(JedisConnectionFactory.class).getHostName())
.isEqualTo("foo");
assertThat(this.context.getBean(JedisConnectionFactory.class).getPoolConfig()
.getMaxIdle()).isEqualTo(1);
load("spring.redis.host:foo", "spring.redis.lettuce.pool.max-idle:1");
LettuceConnectionFactory cf = this.context.getBean(LettuceConnectionFactory.class);
assertThat(cf.getHostName()).isEqualTo("foo");
assertThat(getDefaultLettucePool(cf).getHostName()).isEqualTo("foo");
assertThat(getDefaultLettucePool(cf).getPoolConfig().getMaxIdle()).isEqualTo(1);
}
@Test
public void testRedisConfigurationWithTimeout() throws Exception {
load("spring.redis.host:foo", "spring.redis.timeout:100");
assertThat(this.context.getBean(JedisConnectionFactory.class).getHostName())
.isEqualTo("foo");
assertThat(this.context.getBean(JedisConnectionFactory.class).getTimeout())
.isEqualTo(100);
LettuceConnectionFactory cf = this.context.getBean(LettuceConnectionFactory.class);
assertThat(cf.getHostName()).isEqualTo("foo");
assertThat(cf.getTimeout()).isEqualTo(100);
}
@Test
@ -117,7 +112,7 @@ public class RedisAutoConfigurationTests {
if (isAtLeastOneNodeAvailable(sentinels)) {
load("spring.redis.sentinel.master:mymaster", "spring.redis.sentinel.nodes:"
+ StringUtils.collectionToCommaDelimitedString(sentinels));
assertThat(this.context.getBean(JedisConnectionFactory.class)
assertThat(this.context.getBean(LettuceConnectionFactory.class)
.isRedisSentinelAware()).isTrue();
}
}
@ -125,12 +120,14 @@ public class RedisAutoConfigurationTests {
@Test
public void testRedisConfigurationWithCluster() throws Exception {
List<String> clusterNodes = Arrays.asList("127.0.0.1:27379", "127.0.0.1:27380");
if (isAtLeastOneNodeAvailable(clusterNodes)) {
load("spring.redis.cluster.nodes[0]:" + clusterNodes.get(0),
"spring.redis.cluster.nodes[1]:" + clusterNodes.get(1));
assertThat(this.context.getBean(JedisConnectionFactory.class)
.getClusterConnection()).isNotNull();
}
load("spring.redis.cluster.nodes[0]:" + clusterNodes.get(0),
"spring.redis.cluster.nodes[1]:" + clusterNodes.get(1));
assertThat(this.context.getBean(LettuceConnectionFactory.class)
.getClusterConnection()).isNotNull();
}
private DefaultLettucePool getDefaultLettucePool(LettuceConnectionFactory factory) {
return (DefaultLettucePool) ReflectionTestUtils.getField(factory, "pool");
}
private boolean isAtLeastOneNodeAvailable(List<String> nodes) {
@ -144,22 +141,23 @@ public class RedisAutoConfigurationTests {
}
private boolean isAvailable(String node) {
Jedis jedis = null;
RedisClient redisClient = null;
try {
String[] hostAndPort = node.split(":");
jedis = new Jedis(hostAndPort[0], Integer.valueOf(hostAndPort[1]));
jedis.connect();
jedis.ping();
redisClient = RedisClient.create(new RedisURI(hostAndPort[0],
Integer.valueOf(hostAndPort[1]), 10, TimeUnit.SECONDS));
StatefulRedisConnection<String, String> connection = redisClient.connect();
connection.sync().ping();
connection.close();
return true;
}
catch (Exception ex) {
return false;
}
finally {
if (jedis != null) {
if (redisClient != null) {
try {
jedis.disconnect();
jedis.close();
redisClient.shutdown(0, 0, TimeUnit.SECONDS);
}
catch (Exception ex) {
// Continue
@ -169,21 +167,11 @@ public class RedisAutoConfigurationTests {
}
private void load(String... environment) {
this.context = doLoad(environment);
}
private AnnotationConfigApplicationContext doLoad(String... environment) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(applicationContext, environment);
applicationContext.register(RedisAutoConfiguration.JedisRedisConnectionConfiguration.class, RedisAutoConfiguration.RedisConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, EnableRedisPropertiesConfiguration.class);
applicationContext.refresh();
return applicationContext;
}
@EnableConfigurationProperties(RedisProperties.class)
private static class EnableRedisPropertiesConfiguration {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(ctx, environment);
ctx.register(RedisAutoConfiguration.class);
ctx.refresh();
this.context = ctx;
}
}

View File

@ -125,7 +125,6 @@
<junit.version>4.12</junit.version>
<lettuce.version>5.0.0.BUILD-SNAPSHOT</lettuce.version>
<liquibase.version>3.5.3</liquibase.version>
<lettuce.version>5.0.0.BUILD-SNAPSHOT</lettuce.version>
<log4j2.version>2.8.2</log4j2.version>
<logback.version>1.2.3</logback.version>
<lombok.version>1.16.16</lombok.version>
@ -571,11 +570,6 @@
<artifactId>antlr</artifactId>
<version>${antlr2.version}</version>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>${lettuce.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
@ -831,6 +825,11 @@
<artifactId>metrics-servlets</artifactId>
<version>${dropwizard-metrics.version}</version>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>${lettuce.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-bom</artifactId>
@ -2338,11 +2337,6 @@
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>${lettuce.version}</version>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>

View File

@ -172,6 +172,11 @@
<artifactId>metrics-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.projectreactor.ipc</groupId>
<artifactId>reactor-netty</artifactId>
@ -748,11 +753,6 @@
<artifactId>jedis</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<optional>true</optional>
</dependency>
<!-- Test dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@ -850,38 +850,28 @@ content into your application; rather pick only the properties that you need.
spring.redis.database=0 # Database index used by the connection factory.
spring.redis.url= # Connection URL, will override host, port and password (user will be ignored), e.g. redis://user:password@example.com:6379
spring.redis.host=localhost # Redis server host.
spring.redis.password= # Login password of the redis server.
spring.redis.ssl=false # Enable SSL support.
spring.redis.jedis.pool.max-active=8 # Max number of connections that can be allocated by the pool at a given time. Use a negative value for no limit.
spring.redis.jedis.pool.max-idle=8 # Max number of "idle" connections in the pool. Use a negative value to indicate an unlimited number of idle connections.
spring.redis.jedis.pool.max-wait=-1 # Maximum amount of time (in milliseconds) a connection allocation should block before throwing an exception when the pool is exhausted. Use a negative value to block indefinitely.
spring.redis.jedis.pool.min-idle=0 # Target for the minimum number of idle connections to maintain in the pool. This setting only has an effect if it is positive.
spring.redis.port=6379 # Redis server port.
spring.redis.sentinel.master= # Name of Redis server.
spring.redis.sentinel.nodes= # Comma-separated list of host:port pairs.
spring.redis.timeout=0 # Connection timeout in milliseconds.
spring.redis.ssl.enabled=false # Enable SSL support.
spring.redis.ssl.verify-peer=true # Enable SSL peer verification.
spring.redis.ssl.start-tls=false # Enable StartTLS support.
# REDIS JEDIS DRIVER
spring.redis.jedis.pool.max-active=8 # Max number of connections that can be allocated by the pool at a given time. Use a negative value for no limit.
spring.redis.jedis.pool.max-idle=8 # Max number of "idle" connections in the pool. Use a negative value to indicate an unlimited number of idle connections.
spring.redis.jedis.pool.max-wait=-1 # Maximum amount of time (in milliseconds) a connection allocation should block before throwing an exception when the pool is exhausted. Use a negative value to block indefinitely.
spring.redis.jedis.pool.min-idle=0 # Target for the minimum number of idle connections to maintain in the pool. This setting only has an effect if it is positive.
# REDIS LETTUCE DRIVER
spring.redis.lettuce.pool.max-active=8 # Max number of connections that can be allocated by the pool at a given time. Use a negative value for no limit.
spring.redis.lettuce.pool.max-idle=8 # Max number of "idle" connections in the pool. Use a negative value to indicate an unlimited number of idle connections.
spring.redis.lettuce.pool.max-wait=-1 # Maximum amount of time (in milliseconds) a connection allocation should block before throwing an exception when the pool is exhausted. Use a negative value to block indefinitely.
spring.redis.lettuce.pool.min-idle=0 # Target for the minimum number of idle connections to maintain in the pool. This setting only has an effect if it is positive.
spring.redis.lettuce.shutdown-timeout=2000 # Shutdown timeout in milliseconds.
spring.redis.password= # Login password of the redis server.
spring.redis.port=6379 # Redis server port.
spring.redis.sentinel.master= # Name of Redis server.
spring.redis.sentinel.nodes= # Comma-separated list of host:port pairs.
spring.redis.ssl=false # Enable SSL support.
spring.redis.timeout=0 # Connection timeout in milliseconds.
# TRANSACTION ({sc-spring-boot-autoconfigure}/transaction/TransactionProperties.{sc-ext}[TransactionProperties])
spring.transaction.default-timeout= # Default transaction timeout in seconds.
spring.transaction.rollback-on-commit-failure= # Perform the rollback on commit failures.
# ----------------------------------------
# INTEGRATION PROPERTIES
# ----------------------------------------

View File

@ -3075,12 +3075,14 @@ In this example we are using a single application context (the one created by th
listener) and attaching it to the `DispatcherServlet` using an init parameter. This is
normal in a Spring Boot application (you normally only have one application context).
[[howto-use-lettuce-instead-of-jedis]]
=== Use Lettuce instead of Jedis
The Spring Boot Redis starter (`spring-boot-starter-data-redis` in particular) uses
The Spring Boot starter (`spring-boot-starter-data-redis`) uses
https://github.com/xetorthio/jedis/[Jedis] by default. You need to exclude that dependency
and include the https://github.com/lettuce-io/lettuce-core/[Lettuce] one instead. Spring Boot provides a managed dependency
to help make this process as easy as possible.
and include the https://github.com/lettuce-io/lettuce-core/[Lettuce] one instead. Spring
Boot manages that dependency to help make this process as easy as possible.
Example in Maven:
@ -3114,4 +3116,4 @@ Example in Gradle:
compile("io.lettuce:lettuce-core:{lettuce.version}")
// ...
}
----
----