diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/client/ServiceInstance.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/client/ServiceInstance.java new file mode 100644 index 00000000..0060a921 --- /dev/null +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/client/ServiceInstance.java @@ -0,0 +1,11 @@ +package org.springframework.cloud.client; + + +/** + * @author Spencer Gibb + * TODO: name? Server? HostAndPort? Instance? + */ +public interface ServiceInstance { + public String getHost(); + public int getPort(); +} diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerClient.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerClient.java new file mode 100644 index 00000000..500892d6 --- /dev/null +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerClient.java @@ -0,0 +1,15 @@ +package org.springframework.cloud.client.loadbalancer; + +import org.springframework.cloud.client.ServiceInstance; + +/** + * @author Spencer Gibb + */ +public interface LoadBalancerClient { + /** + * Choose a {@see ServiceInstance} from the LoadBalancer for the specified service + * @param serviceId The serviceId to use to look up the LoadBalancer + * @return + */ + public ServiceInstance choose(String serviceId); +} diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonAutoConfiguration.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonAutoConfiguration.java index 867c5141..a3889f98 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonAutoConfiguration.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonAutoConfiguration.java @@ -3,6 +3,7 @@ package org.springframework.cloud.netflix.ribbon; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration; import org.springframework.cloud.netflix.eureka.EurekaRibbonInitializer; import org.springframework.context.annotation.Bean; @@ -10,7 +11,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.web.client.RestTemplate; -import javax.annotation.PostConstruct; import java.util.ArrayList; import java.util.List; @@ -27,19 +27,22 @@ public class RibbonAutoConfiguration { @Bean @ConditionalOnMissingBean(RestTemplate.class) - public RestTemplate restTemplate() { - return new RestTemplate(); + public RestTemplate restTemplate(RibbonInterceptor ribbonInterceptor) { + RestTemplate restTemplate = new RestTemplate(); + List list = new ArrayList<>(); + list.add(ribbonInterceptor); + restTemplate.setInterceptors(list); + return restTemplate; } @Bean - public RibbonInterceptor ribbonInterceptor() { - return new RibbonInterceptor(); + @ConditionalOnMissingBean(LoadBalancerClient.class) + public LoadBalancerClient loadBalancerClient() { + return new RibbonLoadBalancerClient(); } - @PostConstruct - public void init() { - List list = new ArrayList<>(); - list.add(ribbonInterceptor()); - restTemplate().setInterceptors(list); + @Bean + public RibbonInterceptor ribbonInterceptor(LoadBalancerClient loadBalancerClient) { + return new RibbonInterceptor(loadBalancerClient); } } diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonInterceptor.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonInterceptor.java index 2e5f119e..2cf7ea47 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonInterceptor.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonInterceptor.java @@ -1,8 +1,7 @@ package org.springframework.cloud.netflix.ribbon; -import com.netflix.client.ClientFactory; -import com.netflix.loadbalancer.ILoadBalancer; -import com.netflix.loadbalancer.Server; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestInterceptor; @@ -17,6 +16,13 @@ import java.net.URI; * @author Spencer Gibb */ public class RibbonInterceptor implements ClientHttpRequestInterceptor { + + private LoadBalancerClient loadBalancer; + + public RibbonInterceptor(LoadBalancerClient loadBalancer) { + this.loadBalancer = loadBalancer; + } + @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { HttpRequestWrapper wrapper = new HttpRequestWrapper(request) { @@ -24,14 +30,10 @@ public class RibbonInterceptor implements ClientHttpRequestInterceptor { public URI getURI() { URI originalUri = super.getURI(); String serviceName = originalUri.getHost(); - ILoadBalancer loadBalancer = ClientFactory.getNamedLoadBalancer(serviceName); - Server server = loadBalancer.chooseServer(null); - if (server == null) { - throw new IllegalStateException("Unable to locate ILoadBalancer for service: "+ serviceName); - } + ServiceInstance instance = loadBalancer.choose(serviceName); URI uri = UriComponentsBuilder.fromUri(originalUri) - .host(server.getHost()) - .port(server.getPort()) + .host(instance.getHost()) + .port(instance.getPort()) .build() .toUri(); return uri; diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonLoadBalancerClient.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonLoadBalancerClient.java new file mode 100644 index 00000000..88aff43b --- /dev/null +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonLoadBalancerClient.java @@ -0,0 +1,40 @@ +package org.springframework.cloud.netflix.ribbon; + +import com.netflix.client.ClientFactory; +import com.netflix.loadbalancer.ILoadBalancer; +import com.netflix.loadbalancer.Server; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; + +/** + * @author Spencer Gibb + */ +public class RibbonLoadBalancerClient implements LoadBalancerClient { + @Override + public ServiceInstance choose(String serviceId) { + ILoadBalancer loadBalancer = ClientFactory.getNamedLoadBalancer(serviceId); + Server server = loadBalancer.chooseServer(null); + if (server == null) { + throw new IllegalStateException("Unable to locate ILoadBalancer for service: "+ serviceId); + } + return new RibbonServer(server); + } + + private class RibbonServer implements ServiceInstance { + private Server server; + + private RibbonServer(Server server) { + this.server = server; + } + + @Override + public String getHost() { + return server.getHost(); + } + + @Override + public int getPort() { + return server.getPort(); + } + } +}