Skip to content

Commit

Permalink
spring-cloudGH-140: Support for Composite Discovery client (spring-cl…
Browse files Browse the repository at this point in the history
…oud#198)

Add support for Composite Discovery client

* Test that the default discovery client is  present

* Return a local Service instance from Composite Discovery Client

fixes spring-cloudgh-140
  • Loading branch information
bijukunjummen authored and spencergibb committed Jun 30, 2017
1 parent c953240 commit ca06452
Show file tree
Hide file tree
Showing 9 changed files with 312 additions and 90 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package org.springframework.cloud.client.discovery.composite;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;

/**
* A {@link DiscoveryClient} composed of other Discovery Client's and will delegate the
* calls to each of them in order
*
* @author Biju Kunjummen
*/
public class CompositeDiscoveryClient implements DiscoveryClient {

private final List<DiscoveryClient> discoveryClients;

public CompositeDiscoveryClient(List<DiscoveryClient> discoveryClients) {
this.discoveryClients = discoveryClients;
}

@Override
public String description() {
return "Composite Discovery Client";
}

@Override
public ServiceInstance getLocalServiceInstance() {
if (this.discoveryClients != null) {
for (DiscoveryClient discoveryClient : discoveryClients) {
ServiceInstance serviceInstance = discoveryClient.getLocalServiceInstance();
if (serviceInstance != null) {
return serviceInstance;
}
}
}
return null;
}

@Override
public List<ServiceInstance> getInstances(String serviceId) {
if (this.discoveryClients != null) {
for (DiscoveryClient discoveryClient : discoveryClients) {
List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
if (instances != null && instances.size() > 0) {
return instances;
}
}
}
return Collections.emptyList();
}

@Override
public List<String> getServices() {
LinkedHashSet<String> services = new LinkedHashSet<>();
if (this.discoveryClients != null) {
for (DiscoveryClient discoveryClient : discoveryClients) {
List<String> serviceForClient = discoveryClient.getServices();
if (serviceForClient != null) {
services.addAll(serviceForClient);
}
}
}
return new ArrayList<>(services);
}

List<DiscoveryClient> getDiscoveryClients() {
return discoveryClients;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.springframework.cloud.client.discovery.composite;

import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import java.util.List;

/**
* Auto-configuration for Composite Discovery Client.
*
* @author Biju Kunjummen
*/

@Configuration
@AutoConfigureBefore(SimpleDiscoveryClientAutoConfiguration.class)
public class CompositeDiscoveryClientAutoConfiguration {

@Bean
@Primary
public CompositeDiscoveryClient compositeDiscoveryClient(List<DiscoveryClient> discoveryClients) {
return new CompositeDiscoveryClient(discoveryClients);
}

}
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
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;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.util.ClassUtils;

import java.net.URI;

/**
* Spring Boot Auto-Configuration for Simple Properties based Discovery Client
*
* @author Biju Kunjummen
*/

@Configuration
@ConditionalOnMissingBean(DiscoveryClient.class)
@EnableConfigurationProperties
@AutoConfigureBefore(NoopDiscoveryClientAutoConfiguration.class)
public class SimpleDiscoveryClientAutoConfiguration {

Expand Down Expand Up @@ -54,9 +52,9 @@ public SimpleDiscoveryProperties simpleDiscoveryProperties() {
}

@Bean
public DiscoveryClient simpleDiscoveryClient(
SimpleDiscoveryProperties simpleDiscoveryProperties) {
return new SimpleDiscoveryClient(simpleDiscoveryProperties);
@Order(Ordered.LOWEST_PRECEDENCE)
public DiscoveryClient simpleDiscoveryClient() {
return new SimpleDiscoveryClient(simpleDiscoveryProperties());
}

private int findPort() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ org.springframework.cloud.client.loadbalancer.AsyncLoadBalancerAutoConfiguration
org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration,\
org.springframework.cloud.client.serviceregistry.ServiceRegistryAutoConfiguration,\
org.springframework.cloud.commons.util.UtilAutoConfiguration,\
org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClientAutoConfiguration,\
org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package org.springframework.cloud.client.discovery.composite;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Composite Discovery Client should be the one found by default.
*
* @author Biju Kunjummen
*/

@RunWith(SpringRunner.class)
@SpringBootTest
public class CompositeDiscoveryClientAutoConfigurationTests {

@Autowired
private DiscoveryClient discoveryClient;

@Test
public void compositeDiscoveryClientShouldBeTheDefault() {
assertThat(discoveryClient).isInstanceOf(CompositeDiscoveryClient.class);
CompositeDiscoveryClient compositeDiscoveryClient = (CompositeDiscoveryClient) discoveryClient;
assertThat(compositeDiscoveryClient.getDiscoveryClients()).hasSize(2);
assertThat(compositeDiscoveryClient.getDiscoveryClients().get(0).description())
.isEqualTo("A custom discovery client");
}

@Test
public void simpleDiscoveryClientShouldBeHaveTheLowestPrecedence() {
CompositeDiscoveryClient compositeDiscoveryClient = (CompositeDiscoveryClient) discoveryClient;
assertThat(compositeDiscoveryClient.getDiscoveryClients().get(0).description())
.isEqualTo("A custom discovery client");
assertThat(compositeDiscoveryClient.getDiscoveryClients().get(1))
.isInstanceOf(SimpleDiscoveryClient.class);
}

@EnableAutoConfiguration
@Configuration
public static class Config {

@Bean
public DiscoveryClient customDiscoveryClient1() {
return new DiscoveryClient() {
@Override
public String description() {
return "A custom discovery client";
}

@Override
public ServiceInstance getLocalServiceInstance() {
return null;
}

@Override
public List<ServiceInstance> getInstances(String serviceId) {
return null;
}

@Override
public List<String> getServices() {
return null;
}
};
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package org.springframework.cloud.client.discovery.composite;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.test.context.junit4.SpringRunner;

import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Tests for behavior of Composite Discovery Client
*
* @author Biju Kunjummen
*/

@RunWith(SpringRunner.class)
@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",
"spring.cloud.discovery.client.simple.instances.service2[1].uri=https://s2-2:443" })
public class CompositeDiscoveryClientTests {

@Autowired
private DiscoveryClient discoveryClient;

@Test
public void getInstancesByServiceIdShouldDelegateCall() {
assertThat(this.discoveryClient).isInstanceOf(CompositeDiscoveryClient.class);

assertThat(this.discoveryClient.getInstances("service1")).hasSize(2);

ServiceInstance s1 = this.discoveryClient.getInstances("service1").get(0);
assertThat(s1.getHost()).isEqualTo("s1-1");
assertThat(s1.getPort()).isEqualTo(8080);
assertThat(s1.getUri()).isEqualTo(URI.create("http://s1-1:8080"));
assertThat(s1.isSecure()).isEqualTo(false);
}

@Test
public void getServicesShouldAggregateAllServiceNames() {
assertThat(this.discoveryClient.getServices()).containsOnlyOnce("service1", "service2", "custom");
}

@Test
public void getDescriptionShouldBeComposite() {
assertThat(this.discoveryClient.description()).isEqualTo("Composite Discovery Client");
}

@Test
public void getInstancesShouldRespectOrder() {
assertThat(this.discoveryClient.getInstances("custom")).hasSize(1);
assertThat(this.discoveryClient.getInstances("custom")).hasSize(1);
}

@Test
public void getInstancesByUnknownServiceIdShouldReturnAnEmptyList() {
assertThat(this.discoveryClient.getInstances("unknown")).hasSize(0);
}


@Test
public void localServiceInstanceShouldReturnTheFirstMatch() {
assertThat(this.discoveryClient.getLocalServiceInstance().getServiceId()).isEqualTo("service0");
}

@EnableAutoConfiguration
@Configuration
public static class Config {

@Bean
@Order(1)
public DiscoveryClient customDiscoveryClient() {
return new DiscoveryClient() {
@Override
public String description() {
return "A custom discovery client";
}

@Override
public ServiceInstance getLocalServiceInstance() {
return null;
}

@Override
public List<ServiceInstance> getInstances(String serviceId) {
if (serviceId.equals("custom")) {
ServiceInstance s1 = new DefaultServiceInstance("custom", "host",
123, false);
return Arrays.asList(s1);
}
return Collections.emptyList();
}

@Override
public List<String> getServices() {
return Arrays.asList("custom");
}
};
}
}
}
Loading

0 comments on commit ca06452

Please sign in to comment.