实现自己的轻量级http调用工具
本文來源:http://8rr.co/SUbF
本篇文章繼介紹retrofit-spring-boot-starter的實現原理,從零開始介紹如何在spring-boot項目中基于Retrofit實現自己的輕量級http調用工具。
項目源碼:retrofit-spring-boot-starter
確定實現思路
我們首先直接看一下使用retrofit原始API是如何發起一個http請求的。
定義接口
創建接口代理對象
發起請求
可以看到,Retrofit本身已經很好的支持了通過接口發起htp請求。但是如果我們項目每一個業務代碼都要寫上面的樣板代碼,會非常的繁瑣。有沒有一種方式讓用戶只關注接口定義,其它事情全部交給框架自動處理?這個時候我們可能會聯想到spring-boot項目下使用Mybatis,用戶只需要定義Mapper接口和書寫sql即可,完全不用管與JDBC的交互細節。與之類似,我們最終也要實現讓用戶只需要定義HttpService接口,不用管其他底層實現細節。
相關知識介紹
為了方便后面的介紹,我們先得了解一下幾個相關知識點。
spring容器初始化
我們首先要簡單了解一下spring容器初始化。簡單來講,spring容器初始化主要包含以下2個步驟:
注冊Bean定義:掃描并解析配置文件或者某些注解得到Bean屬性(包括beanName、beanClassName、scope、isSingleton等等),然后基于這個bean屬性創建BeanDefinition對象,最后將其注冊到BeanDefinitionRegistry中。
創建Bean實例:根據BeanDefinitionRegistry里面的BeanDefinition信息,創建Bean實例,并將實例對象保存到spring容器中,創建的方式包括反射創建、工廠方法創建和工廠Bean(FactoryBean)創建等等。
當然,實際的spring容器初始化比這復雜的多,考慮到這塊不是本文的重點,暫時這么理解就行。
Retrofit對象簡介
我們已經知道使用Retrofit對象可以創建接口代理對象,接下來看一下Retrofit的UML類圖(只列出了我們關注的依賴):
通過分析UML類圖,我們可以發現,構建Retrofit對象的時候,可以注入以下4個屬性:
HttpUrl:http請求的baseUrl。
CallAdapter:將Call<T>適配為接口方法返回值類型。
Converter:將@Body標記的方法參數序列化為請求體數據;將響應體數據反序列化為響應對象。
OkHttpClient:底層發送http請求的客戶端對象。
而構建OkHttpClient對象的時候,可以注入Interceptor(請求攔截器)和ConnectionPool(連接池)屬性。
因此為了構建Retrofit對象,我們要先創建HttpUrl、CallAdapter、Converter和OkHttpClient;而要構建OkHttpClient對象就得先創建Interceptor和ConnectionPool。
實現詳解
注冊Bean定義
為了實現將HttpService接口代理對象完全交由spring容器管理,首先就得將HttpService接口掃描并注冊到BeanDefinitionRegistry中。spring提供了ImportBeanDefinitionRegistrar接口,支持了自定義注冊BeanDefinition的功能。因此我們先定義RetrofitClientRegistrar類用來實現上述功能。具體實現如下:
RetrofitClientRegistrar
RetrofitClientRegistrar從@RetrofitScan注解中提取出要掃描的基礎包路徑之后,將具體的掃描注冊邏輯交給了ClassPathRetrofitClientScanner處理。
ClassPathRetrofitClientScanner
ClassPathRetrofitClientScanner繼承了ClassPathBeanDefinitionScanner,這是Spring提供的類路徑下BeanDefinition的掃描器。需要注意的一點是:BeanDefinition的beanClass屬性全部設置為了RetrofitFactoryBean.class,同時將接口自身的類型傳遞到了RetrofitFactoryBean的retrofitInterface屬性中。這說明,最終創建Bean實例是通過RetrofitFactoryBean來完成的。
這樣,我們就完成了掃描指定路徑下帶有@RetrofitClient注解的接口,并將其注冊到BeanDefinitionRegistry的功能了。
@RetrofitClient注解要標識在HttpService的接口上!@RetrofitScan指定了要掃描的包路徑。具體可看考源碼。
創建Bean實例
上面已經說了創建Bean實例實際上是通過RetrofitFactoryBean實現的。具體就是實現FactoryBean<T>接口,然后重寫getObject()方法來完成創建接口Bean實例的邏輯。并且,我們也已經知道通過Retrofit對象能夠生成接口代理對象。因此getObject()方法的核心就是構建Retrofit對象,并基于此生成http接口代理對象。
配置項和@RetrofitClient 為了更加靈活的構建Retrofit對象,我們可以通過配置項以及@RetrofitClient注解屬性傳遞一些動態參數信息。@RetrofitClient包含的屬性如下:
baseUrl:用來創建Retrofit的HttpUrl,表示該接口下所有請求都適用的基礎url。
poolName:該接口下請求使用的連接池的名稱,決定了ConnectionPool對象的取值。
connectTimeoutMs/readTimeoutMs/writeTimeoutMs:用于構建OkHttpClient對象的超時時間設置。
logLevel/logStrategy:配置該接口下請求的日志打印級別和日志打印策略,可用來創建日志打印攔截器Interceptor。
RetrofitFactoryBean RetrofitFactoryBean實現邏輯非常復雜,概括起來主要包含以下幾點:
通過配置項數據以及@RetrofitClient注解數據完成了Retrofit對象的構建。
每一個HttpService接口就會構建一個Retrofit對象,每一個Retrofit對象就會構建對應的OkHttpClient對象。
可擴展的注解式攔截器是通過InterceptMark注解標記實現的,路徑攔截匹配是通過BasePathMatchInterceptor實現的。
這樣,我們就完成了創建HttpServiceBean實例的功能了。在使用的時候直接注入HttpService,然后調用其方法就能發送對應的http請求。
結語
總的來說,在spring-boot項目中基于Retrofit實現自己的輕量級http調用工具的核心只有兩點:第一是注冊HttpService接口的BeanDefinition,第二就是構建Retrofit來創建HttpService的代理對象。如需了解更多細節,建議直接查看retrofit-spring-boot-starter源碼。
- End -
由于微信平臺算法改版,公號內容將不再以時間排序展示,如果大家想第一時間看到我們的推送,強烈建議星標我們和給我們多點點【在看】。星標具體步驟為:
總結
以上是生活随笔為你收集整理的实现自己的轻量级http调用工具的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 再见!linux!
- 下一篇: 七夕了!!聊聊《最受欢迎的男友职业排行榜