diff --git a/spring-cloud-config-client/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceBootstrapConfiguration.java b/spring-cloud-config-client/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceBootstrapConfiguration.java index 18fac7b7..7baeb44d 100644 --- a/spring-cloud-config-client/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceBootstrapConfiguration.java +++ b/spring-cloud-config-client/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceBootstrapConfiguration.java @@ -130,7 +130,6 @@ public class PropertySourceBootstrapConfiguration implements } @Configuration - @ConditionalOnProperty(value = "spring.cloud.config.enabled", matchIfMissing = true) protected static class PropertySourceLocatorConfiguration { @Autowired @@ -143,6 +142,7 @@ public class PropertySourceBootstrapConfiguration implements } @Bean + @ConditionalOnProperty(value = "spring.cloud.config.enabled", matchIfMissing = true) public ConfigServicePropertySourceLocator configServicePropertySource() { ConfigServicePropertySourceLocator locator = new ConfigServicePropertySourceLocator( configClientProperties()); diff --git a/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/client/ConfigClientProperties.java b/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/client/ConfigClientProperties.java index 5994fc04..dcad0721 100644 --- a/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/client/ConfigClientProperties.java +++ b/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/client/ConfigClientProperties.java @@ -34,14 +34,15 @@ import org.springframework.web.util.UriComponentsBuilder; public class ConfigClientProperties { public static final String PREFIX = "spring.cloud.config"; - + /** * Flag to say that remote configuration is enabled. Default true; */ private boolean enabled = true; /** - * The default profile to use when fetching remote configuration (comma-separated). Default is "default". + * The default profile to use when fetching remote configuration (comma-separated). + * Default is "default". */ private String profile = "default"; @@ -59,7 +60,7 @@ public class ConfigClientProperties { private Discovery discovery = new Discovery(); private boolean failFast = false; - + private ConfigClientProperties() { } @@ -82,7 +83,7 @@ public class ConfigClientProperties { public String getRawUri() { return extractCredentials()[2]; } - + public String getUri() { return uri; } @@ -225,19 +226,22 @@ public class ConfigClientProperties { + ConfigClientProperties.PREFIX + ".name:${spring.application.name:application}}")); if (environment.containsProperty(ConfigClientProperties.PREFIX + ".profile")) { - override.setProfile(environment.getProperty(ConfigClientProperties.PREFIX + ".profile")); + override.setProfile(environment.getProperty(ConfigClientProperties.PREFIX + + ".profile")); } if (environment.containsProperty(ConfigClientProperties.PREFIX + ".label")) { - override.setLabel(environment.getProperty(ConfigClientProperties.PREFIX + ".label")); + override.setLabel(environment.getProperty(ConfigClientProperties.PREFIX + + ".label")); } return override; } @Override public String toString() { - return "ConfigClientProperties [name=" + name + ", env=" + profile + ", label=" - + label + ", uri=" + uri + ", discovery.enabled=" + discovery.enabled - + ", failFast="+ failFast + "]"; + return "ConfigClientProperties [enabled=" + enabled + ", profile=" + profile + + ", name=" + name + ", label=" + label + ", username=" + username + + ", password=" + password + ", uri=" + uri + ", discovery.enabled=" + + discovery.enabled + ", failFast=" + failFast + "]"; } } diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerBootstrapApplicationListener.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerBootstrapApplicationListener.java new file mode 100644 index 00000000..b1da3ebd --- /dev/null +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerBootstrapApplicationListener.java @@ -0,0 +1,74 @@ +/* + * Copyright 2014-2015 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; + +import java.util.Collections; + +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.core.Ordered; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; + +/** + * Normally you don't want the config server to be a config client itself, so this + * listener disables the config client unless spring.cloud.config.enabled is + * explicitly "true". It has to be "true" at the time this listener is fired, which means + * before the bootstrap.yml is parsed, which in turn means to you need + * to launch the application with an existing primed {@link Environment} (e.g. via System + * properties or a {@link SpringApplicationBuilder}). This is the same rule of precedence + * as for anything else affecting the bootstrap process itself, e.g. setting + * spring.cloud.bootstrap.name to something other than "bootstrap". + * + * @author Dave Syer + * + */ +public class ConfigServerBootstrapApplicationListener implements + ApplicationListener, Ordered { + + public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 4; + + private int order = DEFAULT_ORDER; + + private PropertySource propertySource = new MapPropertySource( + "configServerClient", Collections. singletonMap( + "spring.cloud.config.enabled", "false")); + + public void setOrder(int order) { + this.order = order; + } + + @Override + public int getOrder() { + return this.order; + } + + @Override + public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) { + ConfigurableEnvironment environment = event.getEnvironment(); + if (!environment.resolvePlaceholders("${spring.cloud.config.enabled:false}") + .equalsIgnoreCase("true")) { + if (!environment.getPropertySources().contains(propertySource.getName())) { + environment.getPropertySources().addLast(propertySource); + } + } + } + +} diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerBootstrapConfiguration.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerBootstrapConfiguration.java index a1ce1fbf..afc3621f 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerBootstrapConfiguration.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerBootstrapConfiguration.java @@ -32,21 +32,25 @@ import org.springframework.context.annotation.Import; * @author Dave Syer * */ -@ConditionalOnProperty("spring.cloud.config.server.bootstrap") @Configuration -@Import(ConfigServerConfiguration.class) public class ConfigServerBootstrapConfiguration { - @Autowired - private EnvironmentRepository repository; + @ConditionalOnProperty("spring.cloud.config.server.bootstrap") + @Import(ConfigServerConfiguration.class) + protected static class LocalPropertySourceLocatorConfiguration { - @Autowired - private ConfigClientProperties client; + @Autowired + private EnvironmentRepository repository; + + @Autowired + private ConfigClientProperties client; + + @Bean + public EnvironmentRepositoryPropertySourceLocator environmentRepositoryPropertySourceLocator() { + return new EnvironmentRepositoryPropertySourceLocator(repository, + client.getName(), client.getProfile(), client.getLabel()); + } - @Bean - public EnvironmentRepositoryPropertySourceLocator environmentRepositoryPropertySourceLocator() { - return new EnvironmentRepositoryPropertySourceLocator(repository, - client.getName(), client.getProfile(), client.getLabel()); } } diff --git a/spring-cloud-config-server/src/main/resources/META-INF/spring.factories b/spring-cloud-config-server/src/main/resources/META-INF/spring.factories index 5b4ba62c..5332de41 100644 --- a/spring-cloud-config-server/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-config-server/src/main/resources/META-INF/spring.factories @@ -1,3 +1,7 @@ # Bootstrap components org.springframework.cloud.bootstrap.BootstrapConfiguration=\ -org.springframework.cloud.config.server.ConfigServerBootstrapConfiguration \ No newline at end of file +org.springframework.cloud.config.server.ConfigServerBootstrapConfiguration + +# Application listeners +org.springframework.context.ApplicationListener=\ +org.springframework.cloud.config.server.ConfigServerBootstrapApplicationListener diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/BootstrapConfigServerIntegrationTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/BootstrapConfigServerIntegrationTests.java index 28a0168f..10471582 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/BootstrapConfigServerIntegrationTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/BootstrapConfigServerIntegrationTests.java @@ -21,8 +21,7 @@ import org.springframework.test.context.web.WebAppConfiguration; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = ConfigServerApplication.class) -@IntegrationTest({ "debug", "server.port:0", - "spring.cloud.bootstrap.name:enable-bootstrap" }) +@IntegrationTest({ "server.port:0", "spring.cloud.bootstrap.name:enable-bootstrap" }) @WebAppConfiguration @ActiveProfiles("test") public class BootstrapConfigServerIntegrationTests { @@ -43,8 +42,8 @@ public class BootstrapConfigServerIntegrationTests { Environment environment = new TestRestTemplate().getForObject("http://localhost:" + port + "/foo/development/", Environment.class); assertFalse(environment.getPropertySources().isEmpty()); - assertEquals("bar", environment.getPropertySources().get(0) - .getSource().get("info.foo")); + assertEquals("bar", + environment.getPropertySources().get(0).getSource().get("info.foo")); } @Test diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ConfigClientOffIntegrationTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ConfigClientOffIntegrationTests.java new file mode 100644 index 00000000..4761624d --- /dev/null +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ConfigClientOffIntegrationTests.java @@ -0,0 +1,71 @@ +package org.springframework.cloud.config.server; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.BeanFactoryUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.IntegrationTest; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.boot.test.TestRestTemplate; +import org.springframework.cloud.config.client.ConfigServicePropertySourceLocator; +import org.springframework.cloud.config.environment.Environment; +import org.springframework.cloud.config.server.ConfigClientOffIntegrationTests.TestConfiguration; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = TestConfiguration.class) +@IntegrationTest("server.port:0") +@WebAppConfiguration +@ActiveProfiles("test") +public class ConfigClientOffIntegrationTests { + + @Value("${local.server.port}") + private int port; + + @Autowired + private ApplicationContext context; + + @BeforeClass + public static void init() throws IOException { + ConfigServerTestUtils.prepareLocalRepo(); + } + + @Test + public void contextLoads() { + Environment environment = new TestRestTemplate().getForObject("http://localhost:" + + port + "/foo/development/", Environment.class); + assertTrue(environment.getPropertySources().isEmpty()); + } + + @Test + public void configClientDisabled() throws Exception { + assertEquals(0, BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, + ConfigServicePropertySourceLocator.class).length); + } + + @Configuration + @Import(ConfigServerApplication.class) + protected static class TestConfiguration { + + @Bean + public EnvironmentRepository environmentRepository() { + return Mockito.mock(EnvironmentRepository.class); + } + + } + +} diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ConfigClientOnIntegrationTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ConfigClientOnIntegrationTests.java new file mode 100644 index 00000000..0a0f695f --- /dev/null +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ConfigClientOnIntegrationTests.java @@ -0,0 +1,71 @@ +package org.springframework.cloud.config.server; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.BeanFactoryUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.IntegrationTest; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.boot.test.TestRestTemplate; +import org.springframework.cloud.config.client.ConfigServicePropertySourceLocator; +import org.springframework.cloud.config.environment.Environment; +import org.springframework.cloud.config.server.ConfigClientOnIntegrationTests.TestConfiguration; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = TestConfiguration.class) +@IntegrationTest({ "server.port:0", "spring.cloud.config.enabled:true" }) +@WebAppConfiguration +@ActiveProfiles("test") +public class ConfigClientOnIntegrationTests { + + @Value("${local.server.port}") + private int port; + + @Autowired + private ApplicationContext context; + + @BeforeClass + public static void init() throws IOException { + ConfigServerTestUtils.prepareLocalRepo(); + } + + @Test + public void contextLoads() { + Environment environment = new TestRestTemplate().getForObject("http://localhost:" + + port + "/foo/development/", Environment.class); + assertTrue(environment.getPropertySources().isEmpty()); + } + + @Test + public void configClientEnabled() throws Exception { + assertEquals(1, BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, + ConfigServicePropertySourceLocator.class).length); + } + + @Configuration + @Import(ConfigServerApplication.class) + protected static class TestConfiguration { + + @Bean + public EnvironmentRepository environmentRepository() { + return Mockito.mock(EnvironmentRepository.class); + } + + } + +}