spring-cloud-square源碼速讀(spring-cloud-square-okhttp篇)


歡迎訪問我的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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM