diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/config/DiscoveryClientConfigServiceAutoConfiguration.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/config/DiscoveryClientConfigServiceAutoConfiguration.java new file mode 100644 index 00000000..41b694f2 --- /dev/null +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/config/DiscoveryClientConfigServiceAutoConfiguration.java @@ -0,0 +1,72 @@ +/* + * Copyright 2013-2014 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.netflix.config; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor; +import org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration; +import org.springframework.context.annotation.Configuration; + +import com.netflix.appinfo.ApplicationInfoManager; +import com.netflix.appinfo.EurekaInstanceConfig; +import com.netflix.discovery.DiscoveryManager; +import com.netflix.discovery.EurekaClientConfig; + +/** + * Bootstrap configuration for a config client that wants to lookup the config server via + * discovery. + * + * @author Dave Syer + */ +@ConditionalOnBean({ EurekaDiscoveryClientConfiguration.class }) +@ConditionalOnProperty(value = "spring.cloud.config.discovery.enabled", matchIfMissing = false) +@Configuration +public class DiscoveryClientConfigServiceAutoConfiguration { + + @Autowired + private EurekaClientConfig clientConfig; + + @Autowired + private EurekaInstanceConfig instanceConfig; + + @Autowired + private ConfigurationPropertiesBindingPostProcessor binder; + + @Autowired + private EurekaDiscoveryClientConfiguration lifecycle; + + @PostConstruct + public void init() { + this.lifecycle.stop(); + rebind(this.clientConfig, "eurekaClientConfig"); + rebind(this.instanceConfig, "eurekaInstanceConfig"); + DiscoveryManager.getInstance().getDiscoveryClient().shutdown(); + ApplicationInfoManager.getInstance().initComponent(this.instanceConfig); + DiscoveryManager.getInstance().initComponent(this.instanceConfig, + this.clientConfig); + this.lifecycle.start(); + } + + private void rebind(Object bean, String name) { + this.binder.postProcessBeforeInitialization(bean, name); + } + +} diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/config/DiscoveryClientConfigServiceBootstrapConfiguration.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/config/DiscoveryClientConfigServiceBootstrapConfiguration.java index f60e3be0..5f8a8b53 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/config/DiscoveryClientConfigServiceBootstrapConfiguration.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/config/DiscoveryClientConfigServiceBootstrapConfiguration.java @@ -20,7 +20,7 @@ import lombok.extern.apachecommons.CommonsLog; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.discovery.event.HeartbeatEvent; import org.springframework.cloud.client.discovery.event.HeartbeatMonitor; @@ -35,6 +35,7 @@ import org.springframework.context.event.SmartApplicationListener; import com.netflix.appinfo.InstanceInfo; import com.netflix.discovery.DiscoveryClient; +import com.netflix.discovery.DiscoveryManager; /** * Bootstrap configuration for a config client that wants to lookup the config server via @@ -43,7 +44,7 @@ import com.netflix.discovery.DiscoveryClient; * @author Dave Syer */ @ConditionalOnClass({ DiscoveryClient.class, ConfigServicePropertySourceLocator.class }) -@ConditionalOnExpression("${spring.cloud.config.discovery.enabled:false}") +@ConditionalOnProperty(value = "spring.cloud.config.discovery.enabled", matchIfMissing = false) @Configuration @EnableDiscoveryClient @Import(EurekaClientAutoConfiguration.class) @@ -53,9 +54,6 @@ public class DiscoveryClientConfigServiceBootstrapConfiguration implements private HeartbeatMonitor monitor = new HeartbeatMonitor(); - @Autowired - private DiscoveryClient client; - @Autowired private ConfigClientProperties config; @@ -90,8 +88,11 @@ public class DiscoveryClientConfigServiceBootstrapConfiguration implements private void refresh() { try { log.info("Locating configserver via discovery"); - InstanceInfo server = this.client.getNextServerFromEureka(this.config - .getDiscovery().getServiceId(), false); + InstanceInfo server = DiscoveryManager + .getInstance() + .getDiscoveryClient() + .getNextServerFromEureka(this.config.getDiscovery().getServiceId(), + false); String url = server.getHomePageUrl(); if (server.getMetadata().containsKey("password")) { String user = server.getMetadata().get("user"); diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/DiscoveryManagerInitializer.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/DiscoveryManagerInitializer.java index 5307b086..2e98cc65 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/DiscoveryManagerInitializer.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/DiscoveryManagerInitializer.java @@ -18,6 +18,7 @@ package org.springframework.cloud.netflix.eureka; import org.springframework.beans.factory.annotation.Autowired; +import com.netflix.appinfo.ApplicationInfoManager; import com.netflix.appinfo.EurekaInstanceConfig; import com.netflix.discovery.DiscoveryManager; import com.netflix.discovery.EurekaClientConfig; @@ -38,6 +39,9 @@ public class DiscoveryManagerInitializer { DiscoveryManager.getInstance().initComponent(this.instanceConfig, this.clientConfig); } + if (ApplicationInfoManager.getInstance().getInfo() == null) { + ApplicationInfoManager.getInstance().initComponent(this.instanceConfig); + } } } diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/EurekaDiscoveryClientConfiguration.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/EurekaDiscoveryClientConfiguration.java index 4472b0da..1a58bb5b 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/EurekaDiscoveryClientConfiguration.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/EurekaDiscoveryClientConfiguration.java @@ -23,6 +23,7 @@ import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.PreDestroy; import lombok.extern.apachecommons.CommonsLog; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.actuate.metrics.reader.MetricReader; @@ -75,6 +76,9 @@ public class EurekaDiscoveryClientConfiguration implements SmartLifecycle, Order @Autowired(required = false) private HealthCheckHandler healthCheckHandler; + @Autowired + private DiscoveryManagerInitializer discoveryManagerInitializer; + @Autowired private ApplicationContext context; @@ -94,8 +98,8 @@ public class EurekaDiscoveryClientConfiguration implements SmartLifecycle, Order if (jerseyClientField != null) { try { jerseyClientField.setAccessible(true); - if (DiscoveryManager.getInstance() != null && - DiscoveryManager.getInstance().getDiscoveryClient() != null) { + if (DiscoveryManager.getInstance() != null + && DiscoveryManager.getInstance().getDiscoveryClient() != null) { Object obj = jerseyClientField.get(DiscoveryManager.getInstance() .getDiscoveryClient()); if (obj != null) { @@ -119,7 +123,7 @@ public class EurekaDiscoveryClientConfiguration implements SmartLifecycle, Order // only initialize if nonSecurePort is greater than 0 and it isn't already running // because of containerPortInitializer below if (!this.running.get() && this.instanceConfig.getNonSecurePort() > 0) { - discoveryManagerIntitializer().init(); + this.discoveryManagerInitializer.init(); log.info("Registering application " + this.instanceConfig.getAppname() + " with eureka with status " @@ -142,8 +146,10 @@ public class EurekaDiscoveryClientConfiguration implements SmartLifecycle, Order public void stop() { log.info("Unregistering application " + this.instanceConfig.getAppname() + " with eureka with status OUT_OF_SERVICE"); - ApplicationInfoManager.getInstance().setInstanceStatus( - InstanceStatus.OUT_OF_SERVICE); + if (ApplicationInfoManager.getInstance().getInfo() != null) { + ApplicationInfoManager.getInstance().setInstanceStatus( + InstanceStatus.OUT_OF_SERVICE); + } this.running.set(false); } @@ -172,10 +178,15 @@ public class EurekaDiscoveryClientConfiguration implements SmartLifecycle, Order return this.order; } - @Bean - @ConditionalOnMissingBean(DiscoveryManagerInitializer.class) - public DiscoveryManagerInitializer discoveryManagerIntitializer() { - return new DiscoveryManagerInitializer(); + @Configuration + protected static class DiscoveryManagerInitializerConfiguration { + + @Bean + @ConditionalOnMissingBean(DiscoveryManagerInitializer.class) + public DiscoveryManagerInitializer discoveryManagerInitializer() { + return new DiscoveryManagerInitializer(); + } + } @Bean diff --git a/spring-cloud-netflix-core/src/main/resources/META-INF/spring.factories b/spring-cloud-netflix-core/src/main/resources/META-INF/spring.factories index efee3500..7e84ee29 100644 --- a/spring-cloud-netflix-core/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-netflix-core/src/main/resources/META-INF/spring.factories @@ -1,6 +1,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.netflix.archaius.ArchaiusAutoConfiguration,\ org.springframework.cloud.netflix.config.EurekaClientConfigServerAutoConfiguration,\ +org.springframework.cloud.netflix.config.DiscoveryClientConfigServiceAutoConfiguration,\ org.springframework.cloud.netflix.feign.ribbon.FeignRibbonClientAutoConfiguration,\ org.springframework.cloud.netflix.feign.FeignAutoConfiguration,\ org.springframework.cloud.netflix.hystrix.HystrixAutoConfiguration,\ diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/config/DiscoveryClientConfigServiceAutoConfigurationTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/config/DiscoveryClientConfigServiceAutoConfigurationTests.java new file mode 100644 index 00000000..5b5f5e02 --- /dev/null +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/config/DiscoveryClientConfigServiceAutoConfigurationTests.java @@ -0,0 +1,110 @@ +/* + * Copyright 2013-2014 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.netflix.config; + +import javax.annotation.PostConstruct; + +import org.junit.After; +import org.junit.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.test.EnvironmentTestUtils; +import org.springframework.cloud.config.client.ConfigClientProperties; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.ConfigurableEnvironment; + +import com.netflix.appinfo.ApplicationInfoManager; +import com.netflix.appinfo.InstanceInfo; +import com.netflix.discovery.DiscoveryClient; +import com.netflix.discovery.DiscoveryManager; + +import static org.junit.Assert.assertEquals; +import static org.mockito.BDDMockito.given; + +/** + * @author Dave Syer + */ +public class DiscoveryClientConfigServiceAutoConfigurationTests { + + private AnnotationConfigApplicationContext context; + + private DiscoveryClient client = Mockito.mock(DiscoveryClient.class); + + private InstanceInfo info = InstanceInfo.Builder.newBuilder().setAppName("app") + .setHostName("foo").setHomePageUrl("/", null).build(); + + @After + public void close() { + if (this.context != null) { + if (this.context.getParent() != null) { + ((AnnotationConfigApplicationContext) this.context.getParent()).close(); + } + this.context.close(); + } + } + + @Test + public void onWhenRequested() throws Exception { + given(this.client.getNextServerFromEureka("CONFIGSERVER", false)).willReturn( + this.info); + setup("spring.cloud.config.discovery.enabled=true"); + assertEquals( + 1, + this.context + .getBeanNamesForType(DiscoveryClientConfigServiceAutoConfiguration.class).length); + Mockito.verify(this.client).getNextServerFromEureka("CONFIGSERVER", false); + Mockito.verify(this.client).shutdown(); + ConfigClientProperties locator = this.context + .getBean(ConfigClientProperties.class); + assertEquals("http://foo:7001/", locator.getRawUri()); + assertEquals("bar", ApplicationInfoManager.getInstance().getInfo().getMetadata() + .get("foo")); + } + + private void setup(String... env) { + AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(parent, env); + parent.getDefaultListableBeanFactory().registerSingleton("mockDiscoveryClient", + this.client); + DiscoveryManager.getInstance().setDiscoveryClient(this.client); + parent.register(PropertyPlaceholderAutoConfiguration.class, + DiscoveryClientConfigServiceBootstrapConfiguration.class, + EnvironmentKnobbler.class, ConfigClientProperties.class); + parent.refresh(); + this.context = new AnnotationConfigApplicationContext(); + this.context.setParent(parent); + this.context.register(DiscoveryClientConfigServiceAutoConfiguration.class); + this.context.refresh(); + } + + @Configuration + protected static class EnvironmentKnobbler { + + @Autowired + private ConfigurableEnvironment environment; + + @PostConstruct + public void init() { + EnvironmentTestUtils.addEnvironment(this.environment, + "eureka.instance.metadataMap.foo:bar"); + } + + } + +} diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/config/DiscoveryClientConfigServiceBootstrapConfigurationTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/config/DiscoveryClientConfigServiceBootstrapConfigurationTests.java index 171ff993..a9819837 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/config/DiscoveryClientConfigServiceBootstrapConfigurationTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/config/DiscoveryClientConfigServiceBootstrapConfigurationTests.java @@ -26,6 +26,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext import com.netflix.appinfo.InstanceInfo; import com.netflix.discovery.DiscoveryClient; +import com.netflix.discovery.DiscoveryManager; import static org.junit.Assert.assertEquals; import static org.mockito.BDDMockito.given; @@ -104,6 +105,7 @@ public class DiscoveryClientConfigServiceBootstrapConfigurationTests { EnvironmentTestUtils.addEnvironment(this.context, env); this.context.getDefaultListableBeanFactory().registerSingleton( "mockDiscoveryClient", this.client); + DiscoveryManager.getInstance().setDiscoveryClient(this.client); this.context.register(PropertyPlaceholderAutoConfiguration.class, DiscoveryClientConfigServiceBootstrapConfiguration.class, ConfigClientProperties.class);