发送http请求(2):RestTemplate发送http请求spring
Springcloud源码阅读4-Ribbon负载均衡(下)app
当我在Ribbon的环境下使用RestTemplate发送请求时,一般咱们会像下面这样注入一个restTemplate负载均衡
@Autowired
@LoadBalanced
RestTemplate restTemplate;
复制代码
为啥咱们注入一个带有注解@LoadBalanced标注RestTemplate,此RestTemplate就具备负载均衡的能力,原理是什么呢?ide
在RestTemplate发送http请求一节讲过,RestTemplate能够添加拦截器,在发送请求前,先执行拦截器内容。函数
在Ribbon负载均衡(下)一节讲过,(LoadBalancerClient)RibbonLoadBalancerClient 具备负载均衡的能力。post
猜想@LoadBalanced注解应该就是把这两点结合在了一块儿。ui
这个整合剂,就是LoadBalancerAutoConfiguration配置类,this
@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
//注入全部使用@LoadBalanced的RestTemplate
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
// 对全部的RestTemplate使用RestTemplateCustomizer定制器进行统一处理
@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);
}
}
});
}
@Autowired(required = false)
private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
//LoadBalancerRequest 建立工厂
@Bean
@ConditionalOnMissingBean
public LoadBalancerRequestFactory loadBalancerRequestFactory( LoadBalancerClient loadBalancerClient) {
return new LoadBalancerRequestFactory(loadBalancerClient, transformers);
}
//LoadBalancerInterceptor 拦截器配置类
@Configuration
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig {
// 负载均衡拦截器,看其参数传入的是loadBalancerClient
@Bean
public LoadBalancerInterceptor ribbonInterceptor( LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
// RestTemplate定制器
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer( final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
}
//省略在有RetryTemplate类状况下的分析。
}
复制代码
@LoadBalanced注解的做用是啥呢?看起源码,咱们发现他自身也有一个注解@Qualifier
spa
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}
复制代码
@Qualifier 咱们应该认识,当容器内存在多个同类型的Bean实现类时,咱们能够经过@Qualifier("service1")注解来标识,具体引入哪一个。
此处的@LoadBalanced 其实就是@Qualifier的一种特殊形态。 当咱们使用@LoadBalanced 标注一个Bean定义时,在自动注入的地方,也使用@LoadBalanced 来自动注入对应的Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
复制代码
注入带有@LoadBalanced注解的RestTemplate
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
复制代码
负载均衡拦截器,有了这个拦截器,就能够设置到Restmplate上去,在请求发起以前作负载均衡操做,从多个候选应用中选择出一个。
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
// LoadBalancerClient 负载均衡客户端
private LoadBalancerClient loadBalancer;
// 用于构建出一个Request
private LoadBalancerRequestFactory requestFactory;
... // 省略构造函数(给这两个属性赋值)
@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));
}
}
复制代码
能够看出LoadBalancerInterceptor 会调用loadBalancer#execute()方法作负载均衡,获取一个服务地址出来。并传入一个回调。
LoadBalancerRequestFactory类
public LoadBalancerRequest<ClientHttpResponse> createRequest(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) {
//回掉方法。
return instance -> {
HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance, loadBalancer);
if (transformers != null) {
for (LoadBalancerRequestTransformer transformer : transformers) {
serviceRequest = transformer.transformRequest(serviceRequest, instance);
}
}
return execution.execute(serviceRequest, body);
};
}
复制代码
当负载均衡选择出一个服务地址,apply回调方法,将当前HttpRequest 进行包装,重写其getURI()
@Override
public URI getURI() {
URI uri = this.loadBalancer.reconstructURI(
this.instance, getRequest().getURI());
return uri;
}
复制代码
这样当真正发起请求时,获取的URI就是已经被负载均衡处理过的URI了。
RestTemplate定制器,用来对RestTemplate进行定制化操做,
此配置类注册的定制器,是用来对RestTemplate 设置LoadBalancerInterceptor的。
// RestTemplate定制器
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer( final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
// 给RestTemplate 添加负载均衡拦截器
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
复制代码
固然咱们能够配置其余的RestTemplateCustomizer 来对RestTemplate作其余定制化操做。
而这些RestTemplateCustomizer 定制器,定制操做。统一由配置类中注册的SmartInitializingSingleton触发。
实现该接口类,当全部单例 bean 都初始化完成之后, 容器会回调该接口的方法 afterSingletonsInstantiated。
此配置类中SmartInitializingSingleton 作的操做就是:对哪些RestTemplate,执行哪些定制化操做
// 对全部的RestTemplate使用RestTemplateCustomizer定制器进行统一处理
@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);
}
}
});
}
复制代码
也就说:spring在初始化过程后期,回调此配置类注册的SmartInitializingSingleton的afterSingletonsInstantiated,把上下文中的全部RestTemplateCustomizer 获取到,循环调用每一个定制器的customize方法执行定制操做。其中就包括把LoadBalancerInterceptor设置到RestTemplate中。
至此:RestTemplate 就具备了负载均衡的能力。
有@LoadBalanced 注解的RestTemplate,会被容器注入一个LoadBalancerInterceptor拦截器,从而使RestTemplate 具备负载均衡的能力。
讲完这节,Ribbon负载均衡与RestTemplate发送请求之间的知识点就造成了闭环。
SpringCloud源码阅读0-SpringCloud必备知识
SpringCloud源码阅读1-EurekaServer源码的秘密
SpringCloud源码阅读3-Ribbon负载均衡(上)
Springcloud源码阅读4-Ribbon负载均衡(下)
欢迎你们关注个人公众号【源码行动】,最新我的理解及时奉送。