Spring Cloud
提供了一个接口 DiscoveryClient
, 为 Eureka
或者 consul
等注册中心去实现, getInstances
方法获取注册的实例,一个实例对应一个工程
List<ServiceInstance> getInstances(String serviceId);
看下接口 ServiceInstance
下面两个方法 获取 主机名(IP)/ 端口
String getHost();
int getPort();
注册了实例之后,使用 阻塞式同步RestTemplate
调用 或者 异步非阻塞 WebClient
调用,RestTemplate
为每个HTTP请求创建一个线程,在响应之前一直是阻塞状态,占用系统内存资源。
多个实例 @LoadBalaced
为 RestTemplate
或者 WebClient
做负载均衡的支持,LoadBalancerInterceptor
实现 ClientHttpRequestInterceptor
接口 (intercept
方法)
ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
throws IOException;
通过请求 URL
获取 host
然后使用 LoadBalancerClient
进行调用
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
private LoadBalancerClient loadBalancer;
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) throws IOException {
final URI originalUri = request.getURI();
String serviceName = originalUri.getHost();
Assert.state(serviceName != null,
"Request URI does not contain a valid hostname: " + originalUri);
return this.loadBalancer.execute(serviceName,
this.requestFactory.createRequest(request, body, execution));
}
看下 execute
方法 默认引用的是 RibbonLoadBalancerClient
通过 serviceId
和 调用的实例 ribbonServer
及 请求request
做服务调用
public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint)
throws IOException {
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
Server server = getServer(loadBalancer, hint);
if (server == null) {
throw new IllegalStateException("No instances available for " + serviceId);
}
RibbonServer ribbonServer = new RibbonServer(serviceId, server,
isSecure(server, serviceId),
serverIntrospector(serviceId).getMetadata(server));
return execute(serviceId, ribbonServer, request);
}
配置 RestTemplate
@Configuration
public class RestTemplateConfiguration {
@LoadBalanced
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
.setConnectTimeout(Duration.ofMillis(100))
.setReadTimeout(Duration.ofMillis(500))
.requestFactory(this::requestFactory)
.build();
}
}