-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
RedisSentinelConfiguration.java
297 lines (248 loc) · 8.79 KB
/
RedisSentinelConfiguration.java
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
/*
* Copyright 2014-2019 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
*
* https://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.data.redis.connection;
import static org.springframework.util.StringUtils.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.data.redis.connection.RedisConfiguration.SentinelConfiguration;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Configuration class used for setting up {@link RedisConnection} via {@link RedisConnectionFactory} using connecting
* to <a href="https://redis.io/topics/sentinel">Redis Sentinel(s)</a>. Useful when setting up a high availability Redis
* environment.
*
* @author Christoph Strobl
* @author Thomas Darimont
* @author Mark Paluch
* @since 1.4
*/
public class RedisSentinelConfiguration implements RedisConfiguration, SentinelConfiguration {
private static final String REDIS_SENTINEL_MASTER_CONFIG_PROPERTY = "spring.redis.sentinel.master";
private static final String REDIS_SENTINEL_NODES_CONFIG_PROPERTY = "spring.redis.sentinel.nodes";
private static final String REDIS_SENTINEL_PASSWORD_CONFIG_PROPERTY = "spring.redis.sentinel.password";
private @Nullable NamedNode master;
private Set<RedisNode> sentinels;
private int database;
private RedisPassword dataNodePassword = RedisPassword.none();
private RedisPassword sentinelPassword = RedisPassword.none();
/**
* Creates new {@link RedisSentinelConfiguration}.
*/
public RedisSentinelConfiguration() {
this(new MapPropertySource("RedisSentinelConfiguration", Collections.emptyMap()));
}
/**
* Creates {@link RedisSentinelConfiguration} for given hostPort combinations.
*
* <pre>
* sentinelHostAndPorts[0] = 127.0.0.1:23679 sentinelHostAndPorts[1] = 127.0.0.1:23680 ...
*
* <pre>
*
* @param sentinelHostAndPorts must not be {@literal null}.
* @since 1.5
*/
public RedisSentinelConfiguration(String master, Set<String> sentinelHostAndPorts) {
this(new MapPropertySource("RedisSentinelConfiguration", asMap(master, sentinelHostAndPorts)));
}
/**
* Creates {@link RedisSentinelConfiguration} looking up values in given {@link PropertySource}.
*
* <pre>
* <code>
* spring.redis.sentinel.master=myMaster
* spring.redis.sentinel.nodes=127.0.0.1:23679,127.0.0.1:23680,127.0.0.1:23681
* </code>
* </pre>
*
* @param propertySource must not be {@literal null}.
* @since 1.5
*/
public RedisSentinelConfiguration(PropertySource<?> propertySource) {
Assert.notNull(propertySource, "PropertySource must not be null!");
this.sentinels = new LinkedHashSet<>();
if (propertySource.containsProperty(REDIS_SENTINEL_MASTER_CONFIG_PROPERTY)) {
this.setMaster(propertySource.getProperty(REDIS_SENTINEL_MASTER_CONFIG_PROPERTY).toString());
}
if (propertySource.containsProperty(REDIS_SENTINEL_NODES_CONFIG_PROPERTY)) {
appendSentinels(
commaDelimitedListToSet(propertySource.getProperty(REDIS_SENTINEL_NODES_CONFIG_PROPERTY).toString()));
}
if (propertySource.containsProperty(REDIS_SENTINEL_PASSWORD_CONFIG_PROPERTY)) {
this.setSentinelPassword(propertySource.getProperty(REDIS_SENTINEL_PASSWORD_CONFIG_PROPERTY).toString());
}
}
/**
* Set {@literal Sentinels} to connect to.
*
* @param sentinels must not be {@literal null}.
*/
public void setSentinels(Iterable<RedisNode> sentinels) {
Assert.notNull(sentinels, "Cannot set sentinels to 'null'.");
this.sentinels.clear();
for (RedisNode sentinel : sentinels) {
addSentinel(sentinel);
}
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.SentinelConfiguration#getSentinels()
*/
public Set<RedisNode> getSentinels() {
return Collections.unmodifiableSet(sentinels);
}
/**
* Add sentinel.
*
* @param sentinel must not be {@literal null}.
*/
public void addSentinel(RedisNode sentinel) {
Assert.notNull(sentinel, "Sentinel must not be 'null'.");
this.sentinels.add(sentinel);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.SentinelConfiguration#setMaster(org.springframework.data.redis.connection.NamedNode)
*/
public void setMaster(NamedNode master) {
Assert.notNull(master, "Sentinel master node must not be 'null'.");
this.master = master;
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.SentinelConfiguration#getMaster()
*/
public NamedNode getMaster() {
return master;
}
/**
* @see #setMaster(String)
* @param master The master node name.
* @return this.
*/
public RedisSentinelConfiguration master(String master) {
this.setMaster(master);
return this;
}
/**
* @see #setMaster(NamedNode)
* @param master the master node
* @return this.
*/
public RedisSentinelConfiguration master(NamedNode master) {
this.setMaster(master);
return this;
}
/**
* @see #addSentinel(RedisNode)
* @param sentinel the node to add as sentinel.
* @return this.
*/
public RedisSentinelConfiguration sentinel(RedisNode sentinel) {
this.addSentinel(sentinel);
return this;
}
/**
* @see #sentinel(RedisNode)
* @param host redis sentinel node host name or ip.
* @param port redis sentinel port.
* @return this.
*/
public RedisSentinelConfiguration sentinel(String host, Integer port) {
return sentinel(new RedisNode(host, port));
}
private void appendSentinels(Set<String> hostAndPorts) {
for (String hostAndPort : hostAndPorts) {
addSentinel(readHostAndPortFromString(hostAndPort));
}
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithDatabaseIndex#getDatabase()
*/
@Override
public int getDatabase() {
return database;
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithDatabaseIndex#setDatabase(int)
*/
@Override
public void setDatabase(int index) {
Assert.isTrue(index >= 0, () -> String.format("Invalid DB index '%s' (a positive index required)", index));
this.database = index;
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithPassword#getPassword()
*/
@Override
public RedisPassword getPassword() {
return dataNodePassword;
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithPassword#setPassword(org.springframework.data.redis.connection.RedisPassword)
*/
@Override
public void setPassword(RedisPassword password) {
Assert.notNull(password, "RedisPassword must not be null!");
this.dataNodePassword = password;
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.SentinelConfiguration#setSentinelPassword(org.springframework.data.redis.connection.RedisPassword)
*/
public void setSentinelPassword(RedisPassword sentinelPassword) {
Assert.notNull(sentinelPassword, "SentinelPassword must not be null!");
this.sentinelPassword = sentinelPassword;
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.SentinelConfiguration#setSentinelPassword()
*/
@Override
public RedisPassword getSentinelPassword() {
return sentinelPassword;
}
private RedisNode readHostAndPortFromString(String hostAndPort) {
String[] args = split(hostAndPort, ":");
Assert.notNull(args, "HostAndPort need to be seperated by ':'.");
Assert.isTrue(args.length == 2, "Host and Port String needs to specified as host:port");
return new RedisNode(args[0], Integer.valueOf(args[1]).intValue());
}
/**
* @param master must not be {@literal null} or empty.
* @param sentinelHostAndPorts must not be {@literal null}.
* @return configuration map.
*/
private static Map<String, Object> asMap(String master, Set<String> sentinelHostAndPorts) {
Assert.hasText(master, "Master address must not be null or empty!");
Assert.notNull(sentinelHostAndPorts, "SentinelHostAndPorts must not be null!");
Map<String, Object> map = new HashMap<>();
map.put(REDIS_SENTINEL_MASTER_CONFIG_PROPERTY, master);
map.put(REDIS_SENTINEL_NODES_CONFIG_PROPERTY, StringUtils.collectionToCommaDelimitedString(sentinelHostAndPorts));
return map;
}
}