如果只是想看ribbon的自定义负载均衡配置,请查看: https://www.cnblogs.com/yangxiaohui227/p/13186004.html

注意:

1.RestTemplate 所在jar为:org.springframework.web.client.RestTemplate 说明了其并不依赖springcloud

2. 所以2个springboot项目其实是可以调用的,而并不需要依赖springCloud,如图:

product服务:

order服务:

浏览器访问order服务:

由此可见,服务间调用并不需要依赖springcloud组件,那么,这样调用会存在什么问题呢?

1.ip和端口需要我们在每个调用的接口都要写死

2.如果一个服务做了集群,这样也是只能调用写死的那个服务

解决方案:引入springCloud

改造下:product创建2个实例,架构图如下:

product1的配置:

product2的配置:

order服务自定义轮询算法调用product服务:

调用第一次:

调用第二次:

由此可以见,负载均衡策略已经实现

然而:我们还是要拼接ip和端口,如果我们想通过服务名(spring.application.name)去调用呢:

调用结果跟之前的是一致的,默认使用轮询负载均衡算法; 上面的例子虽然@LoadBalanced不是ribbon的依赖包,但请求过程中最后还是会依赖ribbon进行负载均衡

思考:上面的例子为何能通过http://product/get去访问,我们知道要访问一个服务必须知道Ip和端口,最终要变成http://ip地址:端口/get形式的url

猜想:

1. http://product/get 请求会被拦截

2. 通过http://product/get可以获取到服务名称为product

3. 通过服务名称product 可以获取服务列表

4. 通过服务列表,按照一定的算法获取一个服务,本质就是从一个list集合中获取一个服务,关键就是如何确定下标index

5. 通过服务拿到对应的IP和端口,然后重新构建url

一.解决第一个猜想:http://product/get被拦截,拦截器在哪里,又是什么时候跟restTemplate 扯上关系的

1.1 springboot自动装配机制的理解

1.2 根据springboot自动装配机制,我们找下spring-cloud-netflix-ribbon的源码,可以看到

查看内容:

由此可见,该类会被springboot自动装配,后续的源码分析都会围绕该类来走

1.3分析LoadBalancerAutoConfiguration该类

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration { @LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList(); //只有加了@LoadBalanced注解的RestTemplate就会加到该集合中 @Autowired(required = false)
private List<LoadBalancerRequestTransformer> transformers = 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); //遍历restTemplates,给其添加自定义信息
}
}
});
} @Bean
@ConditionalOnMissingBean
public LoadBalancerRequestFactory loadBalancerRequestFactory(
LoadBalancerClient loadBalancerClient) {
return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);
} @Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig { @Bean
public LoadBalancerInterceptor ribbonInterceptor(
LoadBalancerClient loadBalancerClient,
LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory); //这个就是我们要找的拦截器了
} @Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list); //拦截器在这个里设置到restTempalte中的
};
} } //省略部分代码 }

下面我们看看RestTemplate类的继承结构

1.4 小结: springboot自动装配机制会对META-INF\spring.factories中key为EnableAutoConfiguration的类进行初始化,而ribbon和springcloud集成的文件中含有的类为:

org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration,该类初始化时会先初始化LoadBalancerAutoConfiguration,而LoadBalancerAutoConfiguration这个类是一个配置类,里面含有的@Bean注解的方法返回的类都会
被初始化和注入spring容器,该类会为含有@LoadBalanced注解的RestTemplate类添加拦截器,而拦截器最终会存到父类的一个集合中

之后流程debug调试:

二.解决猜想通过  http://product/get可以获取到服务名称为product

//此处省略部分过程

猜想三和猜想四解决:  通过服务名称product 可以获取服务列表,并通过服务列表取出一个服务

//获取服务列表和和从服务列表中取出一个服务,下一篇博客将会做详细的讲解

猜想五:通过获取的服务进行url重构:

继续调试:

//省略部分调用

至此可以发现,ribbon底层主要是将我们的服务名称替换为ip和端口

附加:RestTemplate的底层调用:

响应结果是如何转换成String的呢?

继续跟进


												

最新文章

  1. How to parse HTML page data in Windows Phone
  2. css布局多列等高
  3. JSON后端页面解析
  4. C++100款开源界面库[转]
  5. springmvc 传递对象数组参数 property path is neither an array nor a List nor a Map
  6. KEIl混合编程步骤详解
  7. USB CCID &quot;复杂&quot;命令拾零?
  8. firefox的window.onerror没有详细的出错提示
  9. 七古&amp;#183;夏泳小梅沙
  10. MVC中发生System.Data.Entity.Validation.DbEntityValidationException验证异常的解决方法
  11. Struts2 Action接收POST请求JSON数据及其实现解析
  12. 2943:小白鼠排队-poj
  13. plus、max、Pro、Edge
  14. Java生成文件夹
  15. Mysql join语句的优化
  16. java实现人民币数字转大写(转)
  17. PHP7 学习笔记(十二)PHPExcel vs PhpSpreadsheet and PHP_XLSXWriter
  18. PgAgent安装、配置、运行
  19. JS实例5
  20. poj 3415 后缀数组 两个字符串中长度不小于 k 的公共子串的个数

热门文章

  1. 夜息seo培训内部教程
  2. python IDE(集成开发环境)——PyCharm的安装
  3. 关于华为服务器 双路E52620安装系统时遇到的问题
  4. Selenium学习整理(Python)
  5. SQL SERVER管理维护计划错误,备份错误,1053/3041/错误18204,严重性16,状态1
  6. 0vscode基本插件
  7. 自编Basic脚本 用BasicIntepreter执行 打印九九乘法表
  8. 与C中printf并列的System.out.printf 用法(转载)
  9. MySQL查询point类型类型的坐标,返回经度纬度
  10. input历史快捷-变黄解决