Spring Cloud Ribbon 源码分析

一.前言

      咱们在前面两篇文章分析了Spring Cloud Eureka 注册中心客户端的源码,在注册中心会有不少同应用名的实例组成集群供客户端调用,这时咱们就须要负载策略来实现如何请求服务.这时咱们就会用到Spring Cloud Ribbon,它是一个服务请求方应用内嵌的一个组件,并非一个服务,也就是说Eureka客户端都集成了Ribbon,在这里不用额外的导入依赖,用法咱们在Ribbon负载均衡---SpringCloud(三)有过介绍,那么如今咱们来分析一下源码,看究竟是怎么实现的;html

二.Ribbon负载均衡的执行过程

2.1 RestTemplate执行请求

        咱们利用restTemplate执行一个请求,最后都会经过org.springframework.web.client.RestTemplate#doExecute方法,主要内容以下:web

try {
            //利用拦截器建立请求
			ClientHttpRequest request = createRequest(url, method);
			if (requestCallback != null) {
				requestCallback.doWithRequest(request);
			}
            //执行请求,负载的功能在这里面实现
			response = request.execute();
			handleResponse(url, method, response);
			if (responseExtractor != null) {
				return responseExtractor.extractData(response);
			}
			else {
				return null;
			}
		}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

三.源码分析

3.1 RestTemplate

        在前面的使用过程当中,咱们知道Ribbon负载均衡主要依赖于RestTemplate实现的,但RestTemplate其实并非Ribbon的组件,咱们看其所在的包可知,该组件在spring-web包下,也就是说RestTemplate只是被Ribbon利用,用于访问外部服务的一个方法,真正实现负载均衡的是咱们加上其上面的注解@LoadBalanced;spring

3.2 RibbonAutoConfiguration

        若是你读了以前分析Spring Cloud Eureka源码分析,相信对***AutoConfiguration很熟悉了吧,延续以前的一向做风,Spring Cloud Ribbon一样也有一个 RibbonAutoConfiguration,先来分析其实例化条件:app

@Configuration
@ConditionalOnClass({ IClient.class, RestTemplate.class, AsyncRestTemplate.class, Ribbon.class})
@RibbonClients
@AutoConfigureAfter(name = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration")
@AutoConfigureBefore({LoadBalancerAutoConfiguration.class, AsyncLoadBalancerAutoConfiguration.class})
@EnableConfigurationProperties(RibbonEagerLoadProperties.class)
public class RibbonAutoConfiguration {
 ....省略内部代码...
}

3.2.1 @Configuration

          这个应该不用介绍了吧,不过也说一句,主要使得该类被Spring感知到,与@EnableAutoConfiguration配合使用的,若是入口类没有@EnableAutoConfiguration,则@Configuration不会生效;负载均衡

3.2.2 @ConditionalOnClass({ IClient.class, RestTemplate.class, AsyncRestTemplate.class, Ribbon.class})

         注解@ConditionalOnClass代表了实例化的条件,当上下文中存在所示的几个类的时候;这几个类是干啥的呢?咱们看一下;异步

3.2.2.1 IClient     

/**
 * A client that can execute a single request. 
 * 
 * @author awang
 *
 */
public interface IClient<S extends ClientRequest, T extends IResponse> {

	/**
	 * Execute the request and return the response. It is expected that there is no retry and all exceptions
     * are thrown directly.
	 */
    public T execute(S request, IClientConfig requestConfig) throws Exception; 
}

       看该类注释能够知道,用于访问服务提供方的一个简单调用方法, 没有重试机制,遇到异常则直接抛出,他是一个接口(interface), 也就是说在这里定义了基础的执行请求的方法,如有在执行请求有其余的操做,由其子类实现  工具

由上图实现接口的子类类名也能够看出;源码分析

3.2.2.2 RestTemplate

        RestTemplate相信你们确定或多或少的接触过,或者使用过相似的工具类;她主要用来创建HTTP链接,访问外部服务的同步模板工具,咱们根据该类的Note也可知,ui

* <p><strong>Note:</strong> by default the RestTemplate relies on standard JDK
 * facilities to establish HTTP connections. You can switch to use a different
 * HTTP library such as Apache HttpComponents, Netty, and OkHttp through the
 * {@link #setRequestFactory} property.

       这里还介绍了其余的相似工具包,你们在项目中也能够应用,看来源码也不不是只介绍关于本身的,也能学到相关其余的东西;url

      RestTemplate提供了六种HTTP方法,Put,Post,Delete,Get,Options,Head,其中区别我就不介绍了,你们能够点击或者自由搜索;总之,RestTemplate提供了不少咱们经常使用的模板方法,很灵活,详细你们打开这个类自由查看吧;

3.2.2.3 AsyncRestTemplate

       与RestTemplate用法相同,与之不一样的是AsyncRestTemplate用于异步调用,这里给你们找了个Demo,自由查看;

3.2.2.4 Ribbon

/**
 * A class that can be used to create {@link com.netflix.ribbon.http.HttpResourceGroup}, {@link com.netflix.ribbon.http.HttpResourceGroup.Builder},
 * and dynamic proxy of service interfaces. It delegates to a default {@link com.netflix.ribbon.RibbonResourceFactory} to do the work.
 * For better configurability or in DI enabled application, it is recommended to use {@link com.netflix.ribbon.RibbonResourceFactory} directly.
 *
 */

3.2.3 @RibbonClients

     用于自定义配置,细粒度的;

@Configuration
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
@Documented
@Import(RibbonClientConfigurationRegistrar.class)
public @interface RibbonClients {

	RibbonClient[] value() default {};

	Class<?>[] defaultConfiguration() default {};

}

     咱们知道,负载均衡的策略有轮询,随机,权重等等...而Ribbon默认的是轮询,若是咱们要指定不一样的策略,就须要在项目入口类使用这个注解导入配置;而一般咱们的服务调用方会调用不少个服务集群,而调用每一个服务的时候负载策略都不同,所以该注解内部又提供了@RibbonClient注解;

     用法:@RibbonClient用于注解在项目入口类上,name为服务提供方,value指定自定义负载策略;

             @RibbonClients用于整合多个@RibbonClient注解;defaultConfiguration为默认的负载策略;

    具体事例咱们以后再提供;//TODO

3.2.4 @AutoConfigureAfter(name = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration")

     说明该配置类实例化在注解中配置类以后,这也能够理解,EurekaClientAutoConfiguration是Eureka客户端的配置,而RibbonAutoConfiguration是客户端的一个组件的配置,确定先有客户端,若是须要,才会有Ribbon的配置;

3.2.5 @AutoConfigureBefore({LoadBalancerAutoConfiguration.class, AsyncLoadBalancerAutoConfiguration.class})

          说明该配置类实例化在注解中配置类以前;注解中类作了什么,咱们接下来展开;

3.2.5.1 LoadBalancerAutoConfiguration

          负载均衡同步请求自动配置类

3.2.5.2 AsyncLoadBalancerAutoConfiguration

        负载均衡异步请求自动配置类

3.2.6 @EnableConfigurationProperties(RibbonEagerLoadProperties.class)

        用于指定是否支持部分调用服务RibbonClientde 预加载;

        在使用Ribbon的时候,常常会遇到一种状况就是第一次执行请求超时,这是因为调用服务的RibbonClient是懒加载的,在第一次请求的时候加载这样就使得第一次请求的时间会很长,容易超过咱们设定的响应超时时间,从而致使响应超时;经过此项配置能够避免这种状况发生;

       在这里经过@EnableConfigurationProperties开启了这个配置类经过外部配置文件的属性配置实例化bean的功能,使得该类能够经过@ConfigurationProperties注解指定配置属性在配置文件中的前缀,并将其值注入到成员变量,实例化成bean;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

待续...

相关文章
相关标签/搜索