欢迎访问我的GitHub

https://github.com/zq2599/blog_demos

内容:所有原创文章分类汇总及配套源码,涉及Java、Docker、Kubernetes、DevOPS等;

前文回顾

  • 本篇是欣宸《spring-cloud-square原创》系列的第三篇,咱们快速回顾一下前面两篇:
  1. 《五分钟搞懂spring-cloud-square》:说清楚了spring-cloud-square是什么
  2. 《spring-cloud-square开发实战(三种类型全覆盖)》:说清楚了spring-cloud-square怎么用
  • 接下来,为了深入了解spring-cloud-square,我打算读它的源码,爱学习的您有没有兴趣一起呢?

阅读源码的动机

  • 先说一下为什么要去看spring-cloud-square源码
  1. spring是java开源项目的典范,它的源码具备很高的质量和参考价值
  2. 和其他spring项目相比,spring-cloud-square的源码少得可怜,花最少的时间阅读spring项目的源码,这事儿我挺有兴趣
  3. 自动装配、拦截器、业务接口自动实现,这些技术都出现在spring-cloud-square项目中,看懂了学会了,对自己的项目有很高的参考价值

把握核心方向

  • 在spring-cloud-square这种集成了多个库的项目中,涉及的源码是很多的,很容易陷入一个又一个代码的细节中(不停的展开涉及的类和源码),因此,这里先确定本次源码分析的核心方向:
  1. okhttp源码,只看关键部分,其余一律跳过
  2. 只想知道在使用spring-cloud-square-okhttp.jar的时候,为何输入服务名就能访问到对应的服务
  • 以上就是这次阅读源码的主方向,在陷入细节时,这个主方向会及时将我拉回来,继续朝既定目标前进

下载源码

  • 下载完毕后解压,用IDEA打开源码,得到的项目结构如下:

  • 今天,咱们的目标就是上图的spring-cloud-square-okhttp子工程,读它源码,学它精髓!

提前小结

  • 总所周知,欣宸文笔水平在CSDN垫底,还喜欢废话,导致很多读者都看不下去,因此这里提前做个小结,将本篇精华直接奉上,如果您时间有限,或者干脆没兴趣深入了解,可以看完小结后直接离开,也不算毫无收获.....

  • 将整个工程源码串起来小结:

  1. spring-cloud-square-okhttp.jar的使用者是个java应用,该应用要写代码实例化OkHttpClient.Builder对象
  2. spring.factories中配置的OkHttpLoadBalancerAutoConfiguration,会被spring框架扫到并实例化
  3. OkHttpLoadBalancerAutoConfiguration中实例化了OkHttpLoadBalancerInterceptor,并将LoadBalancerClient实例传给它
  4. OkHttpLoadBalancerAutoConfiguration中实例化了OkHttpClientBuilderCustomizer接口的实现,这里面是个lambda表达式,功能是将所有Interceptor传给lambda表达式对应的builder
  5. OkHttpLoadBalancerAutoConfiguration中实例化了OkHttpBuilderBeanPostProcessor,当步骤1中的OkHttpClient.Builder对象被实例化后,OkHttpBuilderBeanPostProcessor会调用OkHttpClient.Builder的addInterceptor对象,将OkHttpLoadBalancerInterceptor传给OkHttpClient.Builder
  6. 业务代码远程访问的时候,用OkHttpClient.Builder创建OkHttpClient对象,此时的OkHttpClient就得到了OkHttpLoadBalancerInterceptor,在远程访问时,业务代码传入的URL中是远程服务的名字,但是OkHttpLoadBalancerInterceptor会借助LoadBalancerClient将远程服务的名字替换成对应的IP和端口,然后再执行真正的网络请求
  • 听说一图胜千言,欣宸二把刀的作图技术实在不敢恭维,但还是坚持把重要步骤用图表达出来了,如下所示,希望您能将就着看:

  • 接下来,如果您还想深入研究和了解spring-cloud-square,就随欣宸一起畅游它的源码世界吧

知识点补充(OkHttpClient.Builder.addInterceptor)

  • 首先要补充一个重要知识点:OkHttpClient.Builder.addInterceptor方法的作用是什么?

  • 看源码很简单,就是将interceptor放入集合interceptors中:

    public Builder addInterceptor(Interceptor interceptor) {
if (interceptor == null) throw new IllegalArgumentException("interceptor == null");
interceptors.add(interceptor);
return this;
}
  • builder是为实例化OkHttpClient服务的,去看OkHttpClient的构造方法,发现interceptors被复制过来了:

  • 在使用OkHttpClient访问网络的时候,会执行下图红框中的getResponseWithInterceptorChain:

  • 然后就是经典的链式处理了,所有的interceptor都会被执行,下图展示了如何构造和启动链式处理:

  • 进入proceed内部,可见每次执行proceed方法,都会取出一个interceptor,调用其intercept方法:

  • 以spring-cloud-square框架的OkHttpLoadBalancerInterceptor为例,下图红框中的方法极为重要,这行代码执行后,会回到上一幅图中的proceed方法,继续处理下一个interceptor:

  • 至此可以小结了:OkHttpClient.Builder.addInterceptor方法的作用,是传入一个Interceptor实现类,在OkHttpClient执行网络请求的时候,该Interceptor的intercept方法会被执行,请记住这个小结,后面有大用处!

spring-cloud-square-okhttp

  • spring-cloud-square提供了三种具体的实现,第一种是spring-cloud-loadbalancer + spring-cloud-square-okhttp的组合,而spring-cloud-loadbalancer是另一个项目不在此文中展开,因此,咱们最先看的就是spring-cloud-square-okhttp的源码了

  • 打开项目如下图,我只能感慨两个字:就这?

  • 关于配置文件additional-spring-configuration-metadata.json,在spring文档中有提到,如下图红框,负责处理注解的处理器会将additional-spring-configuration-metadata.json的内容合并到元数据文件中去:

  • 看看additional-spring-configuration-metadata.json的内容,如下,定义了属性okhttp.loadbalancer.enabled的默认值为true:
{
"groups": [
],
"properties": [
{
"name": "okhttp.loadbalancer.enabled",
"type": "java.lang.Boolean",
"description": "Allows disabling OkHttp Spring Cloud LoadBalancer support.",
"defaultValue": "true"
}
]
}
  • 如果您写过自定义starter库,那么您一定知道,整个spring-cloud-square-okhttp项目应该从spring.factories文件看起,这里面会确定那些配置类要被实例化:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.square.okhttp.loadbalancer.OkHttpLoadBalancerAutoConfiguration
  • 可见配置类OkHttpLoadBalancerAutoConfiguration会被实例化,咱们去看看OkHttpLoadBalancerAutoConfiguration.java,如下图,经过一长串分析得到一个结论:OkHttpBuilderBeanPostProcessor被实例化了

  • 再看OkHttpBuilderBeanPostProcessor.java,如下图,重点关注红框中的三个关键点:

  • 回忆《spring-cloud-square开发实战(三种类型全覆盖)》中的代码,咱们在使用spring-cloud-square-okhttp.jar的时候,要自己写一个配置类来实例化OkHttpClient.Builder,如下所示,因此可见:OkHttpBuilderBeanPostProcessor就是给咱们创建的OkHttpClient.Builder实例准备的,简单的说,就是OkHttpClient.Builder在创建后,就有OkHttpBuilderBeanPostProcessor将OkHttpLoadBalancerInterceptor传递给OkHttpClient.Builder:
package com.bolingcavalry.consumer;

import okhttp3.OkHttpClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; @Configuration
class OkHttpClientConfig{
@Bean
@LoadBalanced
public OkHttpClient.Builder okHttpClientBuilder() {
return new OkHttpClient.Builder();
}
}
  • 此刻的您有没有恍然大悟呢?原来如此啊,所谓spring-cloud-square-okhttp,其实就是要求用户自己做一个OkHttpClient.Builder实例,然后spring-cloud-square-okhttp负责将OkHttpLoadBalancerInterceptor塞给OkHttpClient.Builder实例,如此一来,我们在使用OkHttpClient做远程调用的时候,OkHttpLoadBalancerInterceptor的intercept方法就会被执行了!

  • 最后要看的就是OkHttpLoadBalancerInterceptor了,其实聪明的您此刻已经猜到它的作用了,它持有了LoadBalancerClient实例,那么在访问网络的时候,就可以将URL中的服务名抠出来,用LoadBalancerClient查到对应的服务地址,然后OkHttpClient远程访问可以用这个地址了,没错,就是如此:

收获

  • 其实整个源码的核心就是给OkHttpClient塞进去一个Interceptor,这个Interceptor可以将服务名替换成IP和地址,功能仅此而已,但是收获是否会止步于此呢?这是个主观问题,各人的收获都不一样吧,我这最大的收获有以下两点:
  1. OkHttpClient的链式处理很精彩,Interceptor.intercept中强制要求执行chain.proceed方法,让我想起了装饰者模式中的叠加处理逻辑
  2. 如何用spring.factories + AutoConfig + BeanPostProcessor + SpringCloud LoadBalance协同作战,spring-cloud-square-okhttp算是给我上了一课,尤其是OkHttpLoadBalancerAutoConfiguration中三个构造器的顺序注入,让人有种鼓掌叫好的冲动,我能写出这样简洁明快的starter吗?
  • 至此,spring-cloud-square源码速读的spring-cloud-squarespring-cloud-square-okhttp篇已经完成了,在您学习spring的道路上,希望本文能够带给您一些参考
  • 接下来要挑战的是spring-cloud-square的retrofit相关源码,代码量会增加很多,但是,何惧之有?欣宸原创,必不会辜负您的期待!

你不孤单,欣宸原创一路相伴

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 数据库+中间件系列
  6. DevOps系列

欢迎关注公众号:程序员欣宸

微信搜索「程序员欣宸」,我是欣宸,期待与您一同畅游Java世界..

https://github.com/zq2599/blog_demos

spring-cloud-square源码速读(spring-cloud-square-okhttp篇)的更多相关文章

  1. Spring MVC之源码速读之RequestMappingHandlerAdapter

    spring-webmvc-4.3.19.RELEASE 下面来看DispatcherServlet中的执行: /** * Exposes the DispatcherServlet-specific ...

  2. spring-cloud-square源码速读(retrofit + okhttp篇)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos spring-cloud-square系列文章 五分钟 ...

  3. Spring Boot 启动源码解析结合Spring Bean生命周期分析

    转载请注明出处: 1.SpringBoot 源码执行流程图 2. 创建SpringApplication 应用,在构造函数中推断启动应用类型,并进行spring boot自动装配 public sta ...

  4. 源码速读及点睛:HashMap

    Java 8 HashMap的分离链表 从Java 2到Java 1.7,HashMap在分离链表上的改变并不多,他们的算法基本上是相同的.如果我们假设对象的Hash值服从平均分布,那么获取一个对象需 ...

  5. Feign 系列(05)Spring Cloud OpenFeign 源码解析

    Feign 系列(05)Spring Cloud OpenFeign 源码解析 [TOC] Spring Cloud 系列目录(https://www.cnblogs.com/binarylei/p/ ...

  6. Spring IOC 容器源码分析 - 余下的初始化工作

    1. 简介 本篇文章是"Spring IOC 容器源码分析"系列文章的最后一篇文章,本篇文章所分析的对象是 initializeBean 方法,该方法用于对已完成属性填充的 bea ...

  7. Spring源码分析:Spring IOC容器初始化

    概述: Spring 对于Java 开发来说,以及算得上非常基础并且核心的框架了,在有一定开发经验后,阅读源码能更好的提高我们的编码能力并且让我们对其更加理解.俗话说知己知彼,百战不殆.当你对Spri ...

  8. Spring IOC 容器源码分析 - 循环依赖的解决办法

    1. 简介 本文,我们来看一下 Spring 是如何解决循环依赖问题的.在本篇文章中,我会首先向大家介绍一下什么是循环依赖.然后,进入源码分析阶段.为了更好的说明 Spring 解决循环依赖的办法,我 ...

  9. Spring IOC 容器源码分析 - 创建原始 bean 对象

    1. 简介 本篇文章是上一篇文章(创建单例 bean 的过程)的延续.在上一篇文章中,我们从战略层面上领略了doCreateBean方法的全过程.本篇文章,我们就从战术的层面上,详细分析doCreat ...

随机推荐

  1. 【PHP数据结构】队列的相关逻辑操作

    在逻辑结构中,我们已经学习了一个非常经典的结构类型:栈.今天,我们就来学习另外一个也是非常经典的逻辑结构类型:队列.相信不少同学已经使用过 redis . rabbitmq 之类的缓存队列工具.其实, ...

  2. Hadoop-3.1.3安装

    0.创建用户并付权限 sudo useradd iwbdsudo passwd iwbd 配置iwbd用户具有root权限 修改/etc/sudoers文件,找到下面一行(91行),在root下面添加 ...

  3. 记一次 .NET 某上市工业智造 CPU+内存+挂死 三高分析

    一:背景 1. 讲故事 上个月有位朋友加wx告知他的程序有挂死现象,询问如何进一步分析,截图如下: 看这位朋友还是有一定的分析基础,可能玩的少,缺乏一定的分析经验,当我简单分析之后,我发现这个dump ...

  4. Jmeter系列(22)- 常用逻辑控制器(1) | 随机控制器Random Controller

    随机控制器(Random Controller) 该控制器下的请求,请求顺序随机,适用场景一般为顺序性依赖不强的请求,比如:下载文件:浏览商品:访问查询接口 随机控制器下的请求随机,如果勾选了[忽略控 ...

  5. Faster RCNN 改进论文及资料

    1,面向小目标的多尺度Faster RCNN检测算法 黄继鹏等 对高分辨率图像进行下采样和上采样,使得网上获取的数据与实际测试数据分布接近. 下采样:最大池化和平均池化 上采样:线性插值,区域插值,最 ...

  6. JAVA-java内存分配

    二.java-class的内存分配 三.JAVA string类特别之处 String 通过构造方法创建是在堆内存中, 通过直接赋值对象是在方法区的常量里 四.字符串做拼接 非常耗时和浪费内存的原因 ...

  7. 【CTF】msf和impacket联合拿域控内网渗透-拿域控

    前言 掌控安全里面的靶场内网渗透,练练手! 内网渗透拿域控 环境:http://afsgr16-b1ferw.aqlab.cn/?id=1 1.进去一看,典型的sql注入 2.测试了一下,可以爆库,也 ...

  8. 鸿蒙内核源码分析(用栈方式篇) | 程序运行场地谁提供的 | 百篇博客分析OpenHarmony源码 | v20.04

    百篇博客系列篇.本篇为: v20.xx 鸿蒙内核源码分析(用栈方式篇) | 程序运行场地谁提供的 | 51.c.h .o 精读内核源码就绕不过汇编语言,鸿蒙内核有6个汇编文件,读不懂它们就真的很难理解 ...

  9. java SE(未完结)

    数据类型与运算符 数据类型 基础数据类型 数值型 正整型 byte short int long 结尾加(l/L) 浮点型 float 结尾加(f/F) double 字符型 char 只能存储一个字 ...

  10. efcore分表分库原理解析

    ShardingCore ShardingCore 易用.简单.高性能.普适性,是一款扩展针对efcore生态下的分表分库的扩展解决方案,支持efcore2+的所有版本,支持efcore2+的所有数据 ...