Support for Redis backend repository (#1282)
* initial structure for Redis support * redis support pre-implementation * redis support implementation * fixes * changing to stringredistemplate * fixing names of redis beans * #1282 fixing build errors * #1282 fixing test errors * #1282 fixing failed tests * #1282 adding documentation * #1282 fixing documentation
This commit is contained in:
committed by
Ryan Baxter
parent
cbeceaaefd
commit
8bb4cc68b2
@@ -757,6 +757,52 @@ The database needs to have a table called `PROPERTIES` with columns called `APPL
|
||||
All fields are of type String in Java, so you can make them `VARCHAR` of whatever length you need.
|
||||
Property values behave in the same way as they would if they came from Spring Boot properties files named `{application}-{profile}.properties`, including all the encryption and decryption, which will be applied as post-processing steps (that is, not in the repository implementation directly).
|
||||
|
||||
==== Redis Backend
|
||||
|
||||
Spring Cloud Config Server supports Redis as a backend for configuration properties.
|
||||
You can enable this feature by adding a dependency to link:https://spring.io/projects/spring-data-redis[Spring Data Redis].
|
||||
|
||||
[source,xml,indent=0]
|
||||
.pom.xml
|
||||
----
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
----
|
||||
|
||||
The following configuration uses Spring Data `RedisTemplate` to access a Redis. We can use `spring.redis.*` properties to override default connection settings.
|
||||
|
||||
[source,yaml]
|
||||
----
|
||||
spring:
|
||||
profiles:
|
||||
active: redis
|
||||
redis:
|
||||
host: redis
|
||||
port: 16379
|
||||
----
|
||||
|
||||
The properties should be stored as fields in a hash. The name of hash should be the same as `spring.application.name` property or conjunction of `spring.application.name` and `spring.profiles.active[n]`.
|
||||
[source,sh]
|
||||
----
|
||||
HMSET sample-app server.port "8100" sample.topic.name "test" test.property1 "property1"
|
||||
----
|
||||
|
||||
After executing the command visible above a hash should contain the following keys with values:
|
||||
----
|
||||
HGETALL sample-app
|
||||
{
|
||||
"server.port": "8100",
|
||||
"sample.topic.name": "test",
|
||||
"test.property1": "property1"
|
||||
}
|
||||
----
|
||||
|
||||
NOTE: When no profile is specified `default` will be used.
|
||||
|
||||
==== CredHub Backend
|
||||
|
||||
Spring Cloud Config Server supports link:https://docs.cloudfoundry.org/credhub[CredHub] as a backend for configuration properties.
|
||||
|
||||
@@ -28,6 +28,11 @@
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-config-client</artifactId>
|
||||
@@ -100,6 +105,12 @@
|
||||
<artifactId>org.eclipse.jgit.junit.http</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>it.ozimov</groupId>
|
||||
<artifactId>embedded-redis</artifactId>
|
||||
<version>0.7.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -54,6 +54,9 @@ import org.springframework.cloud.config.server.environment.MultipleJGitEnvironme
|
||||
import org.springframework.cloud.config.server.environment.NativeEnvironmentProperties;
|
||||
import org.springframework.cloud.config.server.environment.NativeEnvironmentRepository;
|
||||
import org.springframework.cloud.config.server.environment.NativeEnvironmentRepositoryFactory;
|
||||
import org.springframework.cloud.config.server.environment.RedisEnvironmentProperties;
|
||||
import org.springframework.cloud.config.server.environment.RedisEnvironmentRepository;
|
||||
import org.springframework.cloud.config.server.environment.RedisEnvironmentRepositoryFactory;
|
||||
import org.springframework.cloud.config.server.environment.SearchPathCompositeEnvironmentRepository;
|
||||
import org.springframework.cloud.config.server.environment.SvnEnvironmentRepositoryFactory;
|
||||
import org.springframework.cloud.config.server.environment.SvnKitEnvironmentProperties;
|
||||
@@ -69,6 +72,7 @@ import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.credhub.core.CredHubOperations;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
/**
|
||||
@@ -81,12 +85,13 @@ import org.springframework.jdbc.core.JdbcTemplate;
|
||||
@Configuration
|
||||
@EnableConfigurationProperties({ SvnKitEnvironmentProperties.class,
|
||||
CredhubEnvironmentProperties.class, JdbcEnvironmentProperties.class,
|
||||
NativeEnvironmentProperties.class, VaultEnvironmentProperties.class })
|
||||
NativeEnvironmentProperties.class, VaultEnvironmentProperties.class,
|
||||
RedisEnvironmentProperties.class })
|
||||
@Import({ CompositeRepositoryConfiguration.class, JdbcRepositoryConfiguration.class,
|
||||
VaultRepositoryConfiguration.class, CredhubConfiguration.class,
|
||||
CredhubRepositoryConfiguration.class, SvnRepositoryConfiguration.class,
|
||||
NativeRepositoryConfiguration.class, GitRepositoryConfiguration.class,
|
||||
DefaultRepositoryConfiguration.class })
|
||||
RedisRepositoryConfiguration.class, DefaultRepositoryConfiguration.class })
|
||||
public class EnvironmentRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
@@ -199,6 +204,19 @@ public class EnvironmentRepositoryConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(StringRedisTemplate.class)
|
||||
static class RedisFactoryConfig {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(StringRedisTemplate.class)
|
||||
public RedisEnvironmentRepositoryFactory redisEnvironmentRepositoryFactory(
|
||||
StringRedisTemplate redis) {
|
||||
return new RedisEnvironmentRepositoryFactory(redis);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(CredHubOperations.class)
|
||||
static class CredhubFactoryConfig {
|
||||
@@ -312,6 +330,21 @@ class JdbcRepositoryConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Profile("redis")
|
||||
@ConditionalOnClass(StringRedisTemplate.class)
|
||||
class RedisRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(StringRedisTemplate.class)
|
||||
public RedisEnvironmentRepository redisEnvironmentRepository(
|
||||
RedisEnvironmentRepositoryFactory factory,
|
||||
RedisEnvironmentProperties environmentProperties) {
|
||||
return factory.build(environmentProperties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Profile("composite")
|
||||
class CompositeRepositoryConfiguration {
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2018-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
|
||||
*
|
||||
* 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.cloud.config.server.environment;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.config.server.support.EnvironmentRepositoryProperties;
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
/**
|
||||
* @author Piotr Mińkowski
|
||||
*/
|
||||
@ConfigurationProperties("spring.cloud.config.server.redis")
|
||||
public class RedisEnvironmentProperties implements EnvironmentRepositoryProperties {
|
||||
|
||||
private int order = Ordered.LOWEST_PRECEDENCE;
|
||||
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2018-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
|
||||
*
|
||||
* 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.cloud.config.server.environment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.cloud.config.environment.Environment;
|
||||
import org.springframework.cloud.config.environment.PropertySource;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Piotr Mińkowski
|
||||
*/
|
||||
public class RedisEnvironmentRepository implements EnvironmentRepository {
|
||||
|
||||
private final StringRedisTemplate redis;
|
||||
|
||||
private final RedisEnvironmentProperties properties;
|
||||
|
||||
public RedisEnvironmentRepository(StringRedisTemplate redis,
|
||||
RedisEnvironmentProperties properties) {
|
||||
this.redis = redis;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Environment findOne(String application, String profile, String label) {
|
||||
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
|
||||
Environment environment = new Environment(application, profiles, label, null,
|
||||
null);
|
||||
final List<String> keys = addKeys(application, Arrays.asList(profiles));
|
||||
keys.forEach(it -> {
|
||||
Map<?, ?> m = redis.opsForHash().entries(it);
|
||||
environment.add(new PropertySource("redis:" + it, m));
|
||||
});
|
||||
return environment;
|
||||
}
|
||||
|
||||
private List<String> addKeys(String application, List<String> profiles) {
|
||||
List<String> keys = new ArrayList<>();
|
||||
keys.add(application);
|
||||
for (String profile : profiles) {
|
||||
keys.add(application + "-" + profile);
|
||||
}
|
||||
Collections.reverse(keys);
|
||||
return keys;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2018-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
|
||||
*
|
||||
* 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.cloud.config.server.environment;
|
||||
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
|
||||
/**
|
||||
* @author Piotr Mińkowski
|
||||
*/
|
||||
public class RedisEnvironmentRepositoryFactory implements
|
||||
EnvironmentRepositoryFactory<RedisEnvironmentRepository, RedisEnvironmentProperties> {
|
||||
|
||||
private StringRedisTemplate redis;
|
||||
|
||||
public RedisEnvironmentRepositoryFactory(StringRedisTemplate redis) {
|
||||
this.redis = redis;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RedisEnvironmentRepository build(
|
||||
RedisEnvironmentProperties environmentProperties) {
|
||||
return new RedisEnvironmentRepository(this.redis, environmentProperties);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,7 +27,7 @@ import org.springframework.cloud.test.ModifiedClassPathRunner;
|
||||
public class CompositeClasspathTests {
|
||||
|
||||
@RunWith(ModifiedClassPathRunner.class)
|
||||
@ClassPathExclusions("spring-jdbc-*.jar")
|
||||
@ClassPathExclusions({"spring-jdbc-*.jar", "spring-data-redis-*.jar"})
|
||||
public static class JdbcTests {
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2018-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
|
||||
*
|
||||
* 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.cloud.config.server.environment;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import redis.embedded.RedisServer;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest;
|
||||
import org.springframework.cloud.config.environment.Environment;
|
||||
import org.springframework.data.redis.core.BoundHashOperations;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@DataRedisTest
|
||||
@ActiveProfiles("redis")
|
||||
public class RedisEnvironmentRepositoryIntegrationTests {
|
||||
|
||||
private RedisServer redisServer;
|
||||
|
||||
@Before
|
||||
public void startRedis() throws IOException {
|
||||
redisServer = new RedisServer(6379);
|
||||
redisServer.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopRedis() {
|
||||
redisServer.stop();
|
||||
}
|
||||
|
||||
@Autowired
|
||||
StringRedisTemplate redis;
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
BoundHashOperations bound = redis.boundHashOps("foo-bar");
|
||||
bound.put("name", "foo");
|
||||
bound.put("tag", "myapp");
|
||||
|
||||
Environment env = new RedisEnvironmentRepository(redis,
|
||||
new RedisEnvironmentProperties()).findOne("foo", "bar", "");
|
||||
assertThat(env.getName()).isEqualTo("foo");
|
||||
assertThat(env.getPropertySources()).isNotEmpty();
|
||||
assertThat(env.getPropertySources().get(0).getSource().get("tag"))
|
||||
.isEqualTo("myapp");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user