我们知道在springCloud中为RestTemplate贴上@LoadBalanced的注解即实现的对该RestTemplate的uri的替换和负载均衡;具体实现是怎样呢
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration
当启动类贴上EnableAutoConfiguration注解后会将spring容器就会加载RibbonAutoConfiguration
我们主要关注该类的三个地方
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
return () -> restTemplateCustomizers.ifAvailable(customizers -> {
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
});
}
public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint)
throws IOException {
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);// 其中serviceId即为服务名
Server server = getServer(loadBalancer, hint);// 这里就是通过负载均衡策略获取到指的的server
if (server == null) {
throw new IllegalStateException("No instances available for " + serviceId);
}
// 对Server服务实例进行包装对象之外,还存储了服务名、是否使用https标识以及一个Map类型的元数据集合
RibbonServer ribbonServer = new RibbonServer(serviceId, server,
isSecure(server, serviceId),
serverIntrospector(serviceId).getMetadata(server));
return execute(serviceId, ribbonServer, request);
}
@Override
public <T> T execute(String serviceId, ServiceInstance serviceInstance,
LoadBalancerRequest<T> request) throws IOException {
Server server = null;
if (serviceInstance instanceof RibbonServer) {
server = ((RibbonServer) serviceInstance).getServer();
}
if (server == null) {
throw new IllegalStateException("No instances available for " + serviceId);
}
// RibbonLoadBalancerContext用于存储调用情况
RibbonLoadBalancerContext context = this.clientFactory
.getLoadBalancerContext(serviceId);
RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);
try {
// 这里会调用最开始的this.loadBalancer.execute的request参数的实现类的apply方法
T returnVal = request.apply(serviceInstance);
// 存储调用情况
statsRecorder.recordStats(returnVal);
return returnVal;
}
// catch IOException and rethrow so RestTemplate behaves correctly
catch (IOException ex) {
statsRecorder.recordStats(ex);
throw ex;
}
catch (Exception ex) {
statsRecorder.recordStats(ex);
ReflectionUtils.rethrowRuntimeException(ex);
}
return null;
}
public LoadBalancerRequest<ClientHttpResponse> createRequest(
final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) {
return instance -> {
// 将request转为了serviceRequest 主要是将loadBalancer.reconstructURI()的实现来重写里面的getURI()方法
HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance,
this.loadBalancer);
if (this.transformers != null) {
for (LoadBalancerRequestTransformer transformer : this.transformers) {
serviceRequest = transformer.transformRequest(serviceRequest,
instance);
}
}
return execution.execute(serviceRequest, body);
};
}
该方法中的lambda表达式及上文中1.2中的apply的方法实现;这里主要关注HttpRequest serviceRequest转换,将获取uri的方式由原来的getURI()改为loadBalancer.reconstructURI()方法的实现
这样最终即为贴有@LoadBalanced的RestTemplate加上了uri的替换和负载均衡实现
总的来说给出了两个扩展的口子