日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

实现自己的轻量级http调用工具

發布時間:2024/9/15 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 实现自己的轻量级http调用工具 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文來源:http://8rr.co/SUbF

本篇文章繼介紹retrofit-spring-boot-starter的實現原理,從零開始介紹如何在spring-boot項目中基于Retrofit實現自己的輕量級http調用工具

項目源碼:retrofit-spring-boot-starter

確定實現思路

我們首先直接看一下使用retrofit原始API是如何發起一個http請求的。

  • 定義接口

  • public interface GitHubService {@GET("users/{user}/repos")Call<List<Repo>> listRepos(@Path("user") String user);}
  • 創建接口代理對象

  • Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.github.com/").build();// 實際業務場景構建Retrofit比這復雜多了,這里最簡單化處理GitHubService service = retrofit.create(GitHubService.class);
  • 發起請求

  • Call<List<Repo>> repos = service.listRepos("octocat");

    可以看到,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處理。

  • public class RetrofitClientRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, BeanClassLoaderAware {// 省略其它代碼@Overridepublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(RetrofitScan.class.getName()));// 掃描指定路徑下@RetrofitClient注解的接口,并注冊到BeanDefinitionRegistry// 真正的掃描注冊邏輯交給了ClassPathRetrofitClientScanner執行ClassPathRetrofitClientScanner scanner = new ClassPathRetrofitClientScanner(registry, classLoader);if (resourceLoader != null) {scanner.setResourceLoader(resourceLoader);}//指定掃描的基礎包String[] basePackages = getPackagesToScan(attributes);scanner.registerFilters();// 掃描并注冊到BeanDefinitionscanner.doScan(basePackages);}}
  • ClassPathRetrofitClientScanner

    ClassPathRetrofitClientScanner繼承了ClassPathBeanDefinitionScanner,這是Spring提供的類路徑下BeanDefinition的掃描器。需要注意的一點是:BeanDefinition的beanClass屬性全部設置為了RetrofitFactoryBean.class,同時將接口自身的類型傳遞到了RetrofitFactoryBean的retrofitInterface屬性中。這說明,最終創建Bean實例是通過RetrofitFactoryBean來完成的。

  • public class ClassPathRetrofitClientScanner extends ClassPathBeanDefinitionScanner {// 省略其它代碼private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {GenericBeanDefinition definition;for (BeanDefinitionHolder holder : beanDefinitions) {definition = (GenericBeanDefinition) holder.getBeanDefinition();if (logger.isDebugEnabled()) {logger.debug("Creating RetrofitClientBean with name '" + holder.getBeanName()+ "' and '" + definition.getBeanClassName() + "' Interface");}definition.getConstructorArgumentValues().addGenericArgumentValue(Objects.requireNonNull(definition.getBeanClassName()));// beanClass全部設置為RetrofitFactoryBeandefinition.setBeanClass(RetrofitFactoryBean.class);}}}

    這樣,我們就完成了掃描指定路徑下帶有@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實現的。

  • public class RetrofitFactoryBean<T> implements FactoryBean<T>, EnvironmentAware, ApplicationContextAware {// 省略其它代碼public RetrofitFactoryBean(Class<T> retrofitInterface) {this.retrofitInterface = retrofitInterface;}@Override@SuppressWarnings("unchecked")public T getObject() throws Exception {// 接口校驗checkRetrofitInterface(retrofitInterface);// 構建Retrofit對象Retrofit retrofit = getRetrofit(retrofitInterface);// 基于Retrofit創建接口代理對象return retrofit.create(retrofitInterface);}/*** 獲取OkHttpClient實例,一個接口接口對應一個OkHttpClient** @param retrofitClientInterfaceClass retrofitClient接口類* @return OkHttpClient實例*/private synchronized OkHttpClient getOkHttpClient(Class<?> retrofitClientInterfaceClass) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {// 基于各種條件構建OkHttpClient}/*** 獲取Retrofit實例,一個retrofitClient接口對應一個Retrofit實例** @param retrofitClientInterfaceClass retrofitClient接口類* @return Retrofit實例*/private synchronized Retrofit getRetrofit(Class<?> retrofitClientInterfaceClass) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {// 構建retrofit}

    這樣,我們就完成了創建HttpServiceBean實例的功能了。在使用的時候直接注入HttpService,然后調用其方法就能發送對應的http請求。

    結語

    總的來說,在spring-boot項目中基于Retrofit實現自己的輕量級http調用工具的核心只有兩點:第一是注冊HttpService接口的BeanDefinition,第二就是構建Retrofit來創建HttpService的代理對象。如需了解更多細節,建議直接查看retrofit-spring-boot-starter源碼。

    - End -

    由于微信平臺算法改版,公號內容將不再以時間排序展示,如果大家想第一時間看到我們的推送,強烈建議星標我們和給我們多點點【在看】。星標具體步驟為:

    (1)點擊頁面最上方“小詹學Python”,進入公眾號主頁。 (2)點擊右上角的小點點,在彈出頁面點擊“設為星標”,就可以啦。 感謝支持,比心。 與50位技術專家面對面20年技術見證,附贈技術全景圖

    總結

    以上是生活随笔為你收集整理的实现自己的轻量级http调用工具的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。