diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/discovery/simple/SimpleDiscoveryClient.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/discovery/simple/SimpleDiscoveryClient.java index 95aa15ed..c8009540 100644 --- a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/discovery/simple/SimpleDiscoveryClient.java +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/discovery/simple/SimpleDiscoveryClient.java @@ -28,7 +28,7 @@ public class SimpleDiscoveryClient implements DiscoveryClient { @Override public ServiceInstance getLocalServiceInstance() { - return null; + return this.simpleDiscoveryProperties.getLocal(); } @Override diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/discovery/simple/SimpleDiscoveryClientAutoConfiguration.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/discovery/simple/SimpleDiscoveryClientAutoConfiguration.java index 9115daae..5fd8175c 100644 --- a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/discovery/simple/SimpleDiscoveryClientAutoConfiguration.java +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/discovery/simple/SimpleDiscoveryClientAutoConfiguration.java @@ -1,11 +1,19 @@ package org.springframework.cloud.client.discovery.simple; +import java.net.URI; + import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.web.ServerProperties; +import org.springframework.boot.context.embedded.EmbeddedServletContainer; +import org.springframework.boot.context.embedded.EmbeddedWebApplicationContext; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.client.discovery.noop.NoopDiscoveryClientAutoConfiguration; +import org.springframework.cloud.commons.util.InetUtils; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -17,15 +25,52 @@ import org.springframework.context.annotation.Configuration; @Configuration @ConditionalOnMissingBean(DiscoveryClient.class) -@EnableConfigurationProperties(SimpleDiscoveryProperties.class) +@EnableConfigurationProperties @AutoConfigureBefore(NoopDiscoveryClientAutoConfiguration.class) public class SimpleDiscoveryClientAutoConfiguration { + @Autowired(required = false) + private ServerProperties server; + @Autowired - private SimpleDiscoveryProperties simpleDiscoveryProperties; + private ApplicationContext context; + + @Value("${spring.application.name:application}") + private String serviceId; + + @Autowired + private InetUtils inet; @Bean - public DiscoveryClient simpleDiscoveryClient() { + public SimpleDiscoveryProperties simpleDiscoveryProperties() { + SimpleDiscoveryProperties simple = new SimpleDiscoveryProperties(); + simple.getLocal().setServiceId(this.serviceId); + simple.getLocal() + .setUri(URI.create( + "http://" + this.inet.findFirstNonLoopbackHostInfo().getHostname() + + ":" + findPort())); + return simple; + } + + @Bean + public DiscoveryClient simpleDiscoveryClient( + SimpleDiscoveryProperties simpleDiscoveryProperties) { return new SimpleDiscoveryClient(simpleDiscoveryProperties); } + + private int findPort() { + if (this.context instanceof EmbeddedWebApplicationContext) { + EmbeddedServletContainer container = ((EmbeddedWebApplicationContext) this.context) + .getEmbeddedServletContainer(); + if (container != null) { + return container.getPort(); + } + } + if (this.server != null && this.server.getPort() != null + && this.server.getPort() > 0) { + return this.server.getPort(); + } + return 8080; + } + } diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/discovery/simple/SimpleDiscoveryProperties.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/discovery/simple/SimpleDiscoveryProperties.java index 5643edea..e9273b52 100644 --- a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/discovery/simple/SimpleDiscoveryProperties.java +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/discovery/simple/SimpleDiscoveryProperties.java @@ -1,13 +1,16 @@ package org.springframework.cloud.client.discovery.simple; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.cloud.client.ServiceInstance; - import java.net.URI; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import javax.annotation.PostConstruct; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.client.ServiceInstance; + /** * Properties to hold the details of a * {@link org.springframework.cloud.client.discovery.DiscoveryClient} service instances @@ -20,33 +23,67 @@ import java.util.Map; public class SimpleDiscoveryProperties { private Map> instances = new HashMap<>(); + /** + * The properties of the local instance (if it exists). Users should set these + * properties explicitly if they are exporting data (e.g. metrics) that need to be + * identified by the service instance. + */ + private SimpleServiceInstance local = new SimpleServiceInstance(); + public Map> getInstances() { - return instances; + return this.instances; } public void setInstances(Map> instances) { this.instances = instances; } + public SimpleServiceInstance getLocal() { + return this.local; + } + + @PostConstruct + public void init() { + for (String key : this.instances.keySet()) { + for (SimpleServiceInstance instance : this.instances.get(key)) { + instance.setServiceId(key); + } + } + } + public static class SimpleServiceInstance implements ServiceInstance { - private URI resolvedUri; + /** + * The URI of the service instance. Will be parsed to extract the scheme, hos and + * port. + */ + private URI uri; private String host; private int port; private boolean secure; + /** + * Metadata for the service instance. Can be used by discovery clients to modify + * their behaviour per instance, e.g. when load balancing. + */ + private Map metadata = new LinkedHashMap<>(); + /** + * The identifier or name for the service. Multiple instances might share the same + * service id. + */ + private String serviceId; public SimpleServiceInstance() { } - public SimpleServiceInstance(String uri) { + public SimpleServiceInstance(URI uri) { setUri(uri); } - public void setUri(String uri) { - this.resolvedUri = URI.create(uri); - this.host = this.resolvedUri.getHost(); - this.port = this.resolvedUri.getPort(); - String scheme = this.resolvedUri.getScheme(); + public void setUri(URI uri) { + this.uri = uri; + this.host = this.uri.getHost(); + this.port = this.uri.getPort(); + String scheme = this.uri.getScheme(); if ("https".equals(scheme)) { this.secure = true; } @@ -54,7 +91,11 @@ public class SimpleDiscoveryProperties { @Override public String getServiceId() { - return null; + return this.serviceId; + } + + public void setServiceId(String id) { + this.serviceId = id; } @Override @@ -74,12 +115,12 @@ public class SimpleDiscoveryProperties { @Override public URI getUri() { - return this.resolvedUri; + return this.uri; } @Override public Map getMetadata() { - return null; + return this.metadata; } } } diff --git a/spring-cloud-commons/src/test/java/org/springframework/cloud/client/discovery/simple/SimpleDiscoveryClientPropertiesMappingTests.java b/spring-cloud-commons/src/test/java/org/springframework/cloud/client/discovery/simple/SimpleDiscoveryClientPropertiesMappingTests.java index 6b6b7150..b1095976 100644 --- a/spring-cloud-commons/src/test/java/org/springframework/cloud/client/discovery/simple/SimpleDiscoveryClientPropertiesMappingTests.java +++ b/spring-cloud-commons/src/test/java/org/springframework/cloud/client/discovery/simple/SimpleDiscoveryClientPropertiesMappingTests.java @@ -1,5 +1,7 @@ package org.springframework.cloud.client.discovery.simple; +import java.net.URI; + import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -10,8 +12,6 @@ import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; -import java.net.URI; - import static org.assertj.core.api.Assertions.assertThat; /** @@ -21,7 +21,7 @@ import static org.assertj.core.api.Assertions.assertThat; */ @RunWith(SpringRunner.class) -@SpringBootTest(properties = { +@SpringBootTest(properties = { "spring.application.name=service0", "spring.cloud.discovery.client.simple.instances.service1[0].uri=http://s1-1:8080", "spring.cloud.discovery.client.simple.instances.service1[1].uri=https://s1-2:8443", "spring.cloud.discovery.client.simple.instances.service2[0].uri=https://s2-1:8080", @@ -36,23 +36,25 @@ public class SimpleDiscoveryClientPropertiesMappingTests { @Test public void propsShouldGetCleanlyMapped() { - assertThat(props.getInstances().size()).isEqualTo(2); - assertThat(props.getInstances().get("service1").size()).isEqualTo(2); - assertThat(props.getInstances().get("service1").get(0).getHost()) + assertThat(this.props.getInstances().size()).isEqualTo(2); + assertThat(this.props.getInstances().get("service1").size()).isEqualTo(2); + assertThat(this.props.getInstances().get("service1").get(0).getHost()) .isEqualTo("s1-1"); - assertThat(props.getInstances().get("service1").get(0).getPort()).isEqualTo(8080); - assertThat(props.getInstances().get("service1").get(0).getUri()) + assertThat(this.props.getInstances().get("service1").get(0).getPort()) + .isEqualTo(8080); + assertThat(this.props.getInstances().get("service1").get(0).getUri()) .isEqualTo(URI.create("http://s1-1:8080")); - assertThat(props.getInstances().get("service1").get(0).isSecure()) + assertThat(this.props.getInstances().get("service1").get(0).isSecure()) .isEqualTo(false); - assertThat(props.getInstances().get("service2").size()).isEqualTo(2); - assertThat(props.getInstances().get("service2").get(0).getHost()) + assertThat(this.props.getInstances().get("service2").size()).isEqualTo(2); + assertThat(this.props.getInstances().get("service2").get(0).getHost()) .isEqualTo("s2-1"); - assertThat(props.getInstances().get("service2").get(0).getPort()).isEqualTo(8080); - assertThat(props.getInstances().get("service2").get(0).getUri()) + assertThat(this.props.getInstances().get("service2").get(0).getPort()) + .isEqualTo(8080); + assertThat(this.props.getInstances().get("service2").get(0).getUri()) .isEqualTo(URI.create("https://s2-1:8080")); - assertThat(props.getInstances().get("service2").get(0).isSecure()) + assertThat(this.props.getInstances().get("service2").get(0).isSecure()) .isEqualTo(true); } @@ -81,6 +83,14 @@ public class SimpleDiscoveryClientPropertiesMappingTests { assertThat(this.discoveryClient.getInstances("nonexistent")).isEmpty(); } + @Test + public void testGetLocalInstance() { + assertThat(this.discoveryClient.getLocalServiceInstance().getServiceId()) + .isEqualTo("service0"); + assertThat(this.discoveryClient.getLocalServiceInstance().getPort()) + .isEqualTo(8080); + } + @Configuration @EnableAutoConfiguration public static class SampleConfig { diff --git a/spring-cloud-commons/src/test/java/org/springframework/cloud/client/discovery/simple/SimpleDiscoveryClientTests.java b/spring-cloud-commons/src/test/java/org/springframework/cloud/client/discovery/simple/SimpleDiscoveryClientTests.java index a418901c..eb29c205 100644 --- a/spring-cloud-commons/src/test/java/org/springframework/cloud/client/discovery/simple/SimpleDiscoveryClientTests.java +++ b/spring-cloud-commons/src/test/java/org/springframework/cloud/client/discovery/simple/SimpleDiscoveryClientTests.java @@ -26,11 +26,12 @@ public class SimpleDiscoveryClientTests { Map> map = new HashMap<>(); SimpleServiceInstance service1Inst1 = new SimpleServiceInstance( - "http://host1:8080"); + URI.create("http://host1:8080")); SimpleServiceInstance service1Inst2 = new SimpleServiceInstance( - "https://host2:8443"); + URI.create("https://host2:8443")); map.put("service1", Arrays.asList(service1Inst1, service1Inst2)); simpleDiscoveryProperties.setInstances(map); + simpleDiscoveryProperties.init(); this.simpleDiscoveryClient = new SimpleDiscoveryClient(simpleDiscoveryProperties); } @@ -39,9 +40,11 @@ public class SimpleDiscoveryClientTests { List instances = this.simpleDiscoveryClient .getInstances("service1"); assertThat(instances.size()).isEqualTo(2); + assertThat(instances.get(0).getServiceId()).isEqualTo("service1"); assertThat(instances.get(0).getHost()).isEqualTo("host1"); assertThat(instances.get(0).getPort()).isEqualTo(8080); assertThat(instances.get(0).getUri()).isEqualTo(URI.create("http://host1:8080")); assertThat(instances.get(0).isSecure()).isEqualTo(false); + assertThat(instances.get(0).getMetadata()).isNotNull(); } }