Skip to content

Commit 291b0c5

Browse files
committed
Merge pull request #5311 from mp911de:issue/sd-redis-lettuce-driver-autoconfiguration
* pr/5311: Add missing tests Polish "Add Lettuce Redis driver autoconfiguration" Add Lettuce Redis driver autoconfiguration
2 parents 64dae5e + 47783e2 commit 291b0c5

File tree

13 files changed

+879
-281
lines changed

13 files changed

+879
-281
lines changed

spring-boot-autoconfigure/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@
100100
<artifactId>de.flapdoodle.embed.mongo</artifactId>
101101
<optional>true</optional>
102102
</dependency>
103+
<dependency>
104+
<groupId>io.lettuce</groupId>
105+
<artifactId>lettuce-core</artifactId>
106+
<optional>true</optional>
107+
</dependency>
103108
<dependency>
104109
<groupId>io.projectreactor.ipc</groupId>
105110
<artifactId>reactor-netty</artifactId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* Copyright 2012-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.data.redis;
18+
19+
import java.net.UnknownHostException;
20+
21+
import org.apache.commons.pool2.impl.GenericObjectPool;
22+
import redis.clients.jedis.Jedis;
23+
import redis.clients.jedis.JedisPoolConfig;
24+
25+
import org.springframework.beans.factory.ObjectProvider;
26+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
27+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
28+
import org.springframework.context.annotation.Bean;
29+
import org.springframework.context.annotation.Configuration;
30+
import org.springframework.data.redis.connection.RedisClusterConfiguration;
31+
import org.springframework.data.redis.connection.RedisConnectionFactory;
32+
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
33+
import org.springframework.data.redis.connection.jedis.JedisConnection;
34+
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
35+
import org.springframework.util.StringUtils;
36+
37+
/**
38+
* Redis connection configuration using Jedis.
39+
*
40+
* @author Mark Paluch
41+
* @author Stephane Nicoll
42+
*/
43+
@Configuration
44+
@ConditionalOnClass({ GenericObjectPool.class, JedisConnection.class, Jedis.class })
45+
class JedisConnectionConfiguration extends RedisConnectionConfiguration {
46+
47+
private final RedisProperties properties;
48+
49+
JedisConnectionConfiguration(RedisProperties properties,
50+
ObjectProvider<RedisSentinelConfiguration> sentinelConfiguration,
51+
ObjectProvider<RedisClusterConfiguration> clusterConfiguration) {
52+
super(properties, sentinelConfiguration, clusterConfiguration);
53+
this.properties = properties;
54+
}
55+
56+
@Bean
57+
@ConditionalOnMissingBean(RedisConnectionFactory.class)
58+
public JedisConnectionFactory redisConnectionFactory() throws UnknownHostException {
59+
return applyProperties(createJedisConnectionFactory());
60+
}
61+
62+
private JedisConnectionFactory applyProperties(JedisConnectionFactory factory) {
63+
configureConnection(factory);
64+
if (this.properties.isSsl()) {
65+
factory.setUseSsl(true);
66+
}
67+
factory.setDatabase(this.properties.getDatabase());
68+
if (this.properties.getTimeout() > 0) {
69+
factory.setTimeout(this.properties.getTimeout());
70+
}
71+
return factory;
72+
}
73+
74+
private void configureConnection(JedisConnectionFactory factory) {
75+
if (StringUtils.hasText(this.properties.getUrl())) {
76+
configureConnectionFromUrl(factory);
77+
}
78+
else {
79+
factory.setHostName(this.properties.getHost());
80+
factory.setPort(this.properties.getPort());
81+
if (this.properties.getPassword() != null) {
82+
factory.setPassword(this.properties.getPassword());
83+
}
84+
}
85+
}
86+
87+
private void configureConnectionFromUrl(JedisConnectionFactory factory) {
88+
ConnectionInfo connectionInfo = parseUrl(this.properties.getUrl());
89+
factory.setUseSsl(connectionInfo.isUseSsl());
90+
factory.setHostName(connectionInfo.getHostName());
91+
factory.setPort(connectionInfo.getPort());
92+
if (connectionInfo.getPassword() != null) {
93+
factory.setPassword(connectionInfo.getPassword());
94+
}
95+
}
96+
97+
private JedisConnectionFactory createJedisConnectionFactory() {
98+
RedisProperties.Pool pool = this.properties.getJedis().getPool();
99+
JedisPoolConfig poolConfig = pool != null
100+
? jedisPoolConfig(pool) : new JedisPoolConfig();
101+
102+
if (getSentinelConfig() != null) {
103+
return new JedisConnectionFactory(getSentinelConfig(), poolConfig);
104+
}
105+
if (getClusterConfiguration() != null) {
106+
return new JedisConnectionFactory(getClusterConfiguration(), poolConfig);
107+
}
108+
return new JedisConnectionFactory(poolConfig);
109+
}
110+
111+
private JedisPoolConfig jedisPoolConfig(RedisProperties.Pool pool) {
112+
JedisPoolConfig config = new JedisPoolConfig();
113+
config.setMaxTotal(pool.getMaxActive());
114+
config.setMaxIdle(pool.getMaxIdle());
115+
config.setMinIdle(pool.getMinIdle());
116+
config.setMaxWaitMillis(pool.getMaxWait());
117+
return config;
118+
}
119+
120+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/*
2+
* Copyright 2012-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.data.redis;
18+
19+
import java.net.UnknownHostException;
20+
21+
import io.lettuce.core.RedisClient;
22+
import io.lettuce.core.cluster.RedisClusterClient;
23+
import io.lettuce.core.resource.ClientResources;
24+
import io.lettuce.core.resource.DefaultClientResources;
25+
import org.apache.commons.pool2.impl.GenericObjectPool;
26+
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
27+
28+
import org.springframework.beans.factory.ObjectProvider;
29+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
30+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
31+
import org.springframework.context.annotation.Bean;
32+
import org.springframework.context.annotation.Configuration;
33+
import org.springframework.data.redis.connection.RedisClusterConfiguration;
34+
import org.springframework.data.redis.connection.RedisConnectionFactory;
35+
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
36+
import org.springframework.data.redis.connection.lettuce.DefaultLettucePool;
37+
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
38+
import org.springframework.util.StringUtils;
39+
40+
/**
41+
* Redis connection configuration using Lettuce.
42+
*
43+
* @author Mark Paluch
44+
*/
45+
@Configuration
46+
@ConditionalOnClass({ GenericObjectPool.class, RedisClient.class, RedisClusterClient.class })
47+
class LettuceConnectionConfiguration extends RedisConnectionConfiguration {
48+
49+
private final RedisProperties properties;
50+
51+
LettuceConnectionConfiguration(RedisProperties properties,
52+
ObjectProvider<RedisSentinelConfiguration> sentinelConfigurationProvider,
53+
ObjectProvider<RedisClusterConfiguration> clusterConfigurationProvider) {
54+
super(properties, sentinelConfigurationProvider, clusterConfigurationProvider);
55+
this.properties = properties;
56+
}
57+
58+
@Bean(destroyMethod = "shutdown")
59+
@ConditionalOnMissingBean(ClientResources.class)
60+
public DefaultClientResources lettuceClientResources() {
61+
return DefaultClientResources.create();
62+
}
63+
64+
@Bean
65+
@ConditionalOnMissingBean(RedisConnectionFactory.class)
66+
public LettuceConnectionFactory redisConnectionFactory(
67+
ClientResources clientResources) throws UnknownHostException {
68+
return applyProperties(createLettuceConnectionFactory(clientResources));
69+
}
70+
71+
private LettuceConnectionFactory applyProperties(LettuceConnectionFactory factory) {
72+
configureConnection(factory);
73+
if (this.properties.isSsl()) {
74+
factory.setUseSsl(true);
75+
}
76+
if (this.properties.getLettuce() != null) {
77+
RedisProperties.Lettuce lettuce = this.properties.getLettuce();
78+
if (lettuce.getShutdownTimeout() >= 0) {
79+
factory.setShutdownTimeout(
80+
this.properties.getLettuce().getShutdownTimeout());
81+
}
82+
}
83+
return factory;
84+
}
85+
86+
private void configureConnection(LettuceConnectionFactory factory) {
87+
if (StringUtils.hasText(this.properties.getUrl())) {
88+
configureConnectionFromUrl(factory);
89+
}
90+
else {
91+
factory.setHostName(this.properties.getHost());
92+
factory.setPort(this.properties.getPort());
93+
if (this.properties.getPassword() != null) {
94+
factory.setPassword(this.properties.getPassword());
95+
}
96+
factory.setDatabase(this.properties.getDatabase());
97+
if (this.properties.getTimeout() > 0) {
98+
factory.setTimeout(this.properties.getTimeout());
99+
}
100+
}
101+
}
102+
103+
private void configureConnectionFromUrl(LettuceConnectionFactory factory) {
104+
ConnectionInfo connectionInfo = parseUrl(this.properties.getUrl());
105+
factory.setUseSsl(connectionInfo.isUseSsl());
106+
factory.setHostName(connectionInfo.getHostName());
107+
factory.setPort(connectionInfo.getPort());
108+
if (connectionInfo.getPassword() != null) {
109+
factory.setPassword(connectionInfo.getPassword());
110+
}
111+
}
112+
113+
private DefaultLettucePool applyProperties(DefaultLettucePool pool) {
114+
if (StringUtils.hasText(this.properties.getUrl())) {
115+
configureConnectionFromUrl(pool);
116+
}
117+
else {
118+
pool.setHostName(this.properties.getHost());
119+
pool.setPort(this.properties.getPort());
120+
if (this.properties.getPassword() != null) {
121+
pool.setPassword(this.properties.getPassword());
122+
}
123+
pool.setDatabase(this.properties.getDatabase());
124+
}
125+
if (this.properties.getTimeout() > 0) {
126+
pool.setTimeout(this.properties.getTimeout());
127+
}
128+
pool.afterPropertiesSet();
129+
return pool;
130+
}
131+
132+
private void configureConnectionFromUrl(DefaultLettucePool lettucePool) {
133+
ConnectionInfo connectionInfo = parseUrl(this.properties.getUrl());
134+
lettucePool.setHostName(connectionInfo.getHostName());
135+
lettucePool.setPort(connectionInfo.getPort());
136+
if (connectionInfo.getPassword() != null) {
137+
lettucePool.setPassword(connectionInfo.getPassword());
138+
}
139+
}
140+
141+
private LettuceConnectionFactory createLettuceConnectionFactory(
142+
ClientResources clientResources) {
143+
144+
if (getSentinelConfig() != null) {
145+
if (this.properties.getLettuce() != null
146+
&& this.properties.getLettuce().getPool() != null) {
147+
DefaultLettucePool lettucePool = new DefaultLettucePool(
148+
getSentinelConfig());
149+
return new LettuceConnectionFactory(applyProperties(
150+
applyClientResources(lettucePool, clientResources)));
151+
}
152+
return applyClientResources(
153+
new LettuceConnectionFactory(getSentinelConfig()),
154+
clientResources);
155+
}
156+
157+
if (getClusterConfiguration() != null) {
158+
return applyClientResources(
159+
new LettuceConnectionFactory(getClusterConfiguration()),
160+
clientResources);
161+
}
162+
163+
if (this.properties.getLettuce() != null
164+
&& this.properties.getLettuce().getPool() != null) {
165+
GenericObjectPoolConfig config = lettucePoolConfig(
166+
this.properties.getLettuce().getPool());
167+
DefaultLettucePool lettucePool = new DefaultLettucePool(
168+
this.properties.getHost(), this.properties.getPort(), config);
169+
return new LettuceConnectionFactory(applyProperties(
170+
applyClientResources(lettucePool, clientResources)));
171+
}
172+
173+
return applyClientResources(new LettuceConnectionFactory(), clientResources);
174+
}
175+
176+
private DefaultLettucePool applyClientResources(DefaultLettucePool lettucePool,
177+
ClientResources clientResources) {
178+
lettucePool.setClientResources(clientResources);
179+
return lettucePool;
180+
}
181+
182+
private LettuceConnectionFactory applyClientResources(
183+
LettuceConnectionFactory factory, ClientResources clientResources) {
184+
factory.setClientResources(clientResources);
185+
return factory;
186+
}
187+
188+
private GenericObjectPoolConfig lettucePoolConfig(RedisProperties.Pool props) {
189+
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
190+
config.setMaxTotal(props.getMaxActive());
191+
config.setMaxIdle(props.getMaxIdle());
192+
config.setMinIdle(props.getMinIdle());
193+
config.setMaxWaitMillis(props.getMaxWait());
194+
return config;
195+
}
196+
197+
}

0 commit comments

Comments
 (0)