Spring Cloud Ribbon 源码分析

我的梦境 提交于 2019-11-30 00:24:41

一.前言

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

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

2.1 RestTemplate执行请求

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

		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;

3.2 RibbonAutoConfiguration

        如果你读了之前分析Spring Cloud Eureka源码分析,相信对***AutoConfiguration很熟悉了吧,延续之前的一贯作风,Spring Cloud Ribbon同样也有一个 RibbonAutoConfiguration,先来分析其实例化条件:

@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也可知,

 * <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.

       这里还介绍了其他的类似工具包,大家在项目中也可以应用,看来源码也不不是只介绍关于自己的,也能学到相关其他的东西;

      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;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

待续...

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!