本文已参与「新人创作礼」活动,一起开启掘金创作之路。
拦截器机制改变RestTemplate的行为
LoadBalancerAutoConfiguration通过RestTemplateCustomizer给RestTemplate设置一个拦截器(LoadBalancerInterceptor)。
如果对RestTemplate执行某个操作,相当于发起一个http请求,此时不会由RestTemplate自己原生的功能来实现,而是会由拦截器来实现这个请求http服务的一个功能。
LoadBalancerInterceptor拦截器
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
private LoadBalancerClient loadBalancer;
private LoadBalancerRequestFactory requestFactory;
public LoadBalancerInterceptor(LoadBalancerClient loadBalancer,
LoadBalancerRequestFactory requestFactory) {
this.loadBalancer = loadBalancer;
this.requestFactory = requestFactory;
}
public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
// for backwards compatibility
this(loadBalancer, new LoadBalancerRequestFactory(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));
}
}
在执行下面那行代码的时候,其实是将这个请求给封装了一下,将 http://ServiceA/product/ 封装到了HttpRequest(HTTP请求报文)里面去,然后将HttpRequest加上请求体的字节数组,ClientHttpRequestExecution(HTTP请求报文客户端执行,包含一个拦截器集合的迭代器,用来迭代执行拦截器)
restTemplate.getForObject("http://ServiceA/product/", String.class);
restTemplate 是实现了 InterceptingHttpAccessor 接口的,具备支持拦截器的能力。
相当于是底层调用了拦截器里的intercept()方法,实际的这个请求的逻辑,不再由RestTemplate原来原生的默认的逻辑来实现,而是由intercept()拦截方法来实现了。
final URI originalUri = request.getURI();
String serviceName = originalUri.getHost();
request.getURI(),获取到的就是:http://ServiceA/product/
originalUri.getHost(),获取到的就是:ServiceA
serviceName,服务名称
Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
如果你的获取到的服务名称是null,那么就打印异常日志,告诉你,你的请求的url地址里面没有包含合格的hostname主机名
在构造LoadBalancerInterceptor的时候,其实传进来了一个LoadBalancerClient。
LoadBalancerInterceptor,拦截掉RestTemplate所有的执行的请求,然后从url地址里获取hostname作为服务名称,然后找LoadBalancerClient去执行对应的负载均衡的请求
LoadBalancerClient 实现 ServiceInstanceChooser接口
1. ServiceInstance choose(String serviceId);从LoadBalancer中更具ServiceId获取一个具体的服务实例
2. <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException;根据服务实例,LoadBalancerRequest(负载均衡器请求报文)执行请求
3. URI reconstructURI(ServiceInstance instance, URI original);根据服务实例和原来的URI重新构造一个URI。