當前位置: 妍妍網 > 碼農

不好意思,HttpClient 該換了!

2024-06-18碼農

來源:juejin.cn/post/6898485806587969544

SpringBoot 計畫直接使用 okhttp httpClient 或者 RestTemplate 發起 HTTP 請求,既繁瑣又不方便統一管理。因此,在這裏推薦一個適用於 SpringBoot 計畫的輕量級HTTP客戶端框架retrofit-spring-boot-starter,使用非常簡單方便,同時又提供諸多功能增強。目前計畫已經更新至 2.2.2 版本,並且會持續進行叠代最佳化。

前言

Retrofit 是適用於 Android Java 且型別安全的HTTP客戶端,其最大的特性的是 支持透過 介面 的方式發起HTTP請求 。而 spring-boot 是使用最廣泛的Java開發框架,但是 Retrofit 官方沒有支持與 spring-boot 框架快速整合,因此我們開發了 retrofit-spring-boot-starter

retrofit-spring-boot-starter 實作了 Retrofit spring-boot 框架快速整合,並且支持了諸多功能增強,極大簡化開發

🚀計畫持續最佳化叠代。

功能特性

  • 自訂註入OkHttpClient

  • 註解式攔截器

  • 連線池管理

  • 日誌打印

  • 請求重試

  • 錯誤解碼器

  • 全域攔截器

  • 熔斷降級

  • 微服務之間的HTTP呼叫

  • 呼叫介面卡

  • 數據轉換器

  • 快速使用

    引入依賴

    <dependency>
    <groupId>com.github.lianjiatech</groupId>
    <artifactId>retrofit-spring-boot-starter</artifactId>
    <version>2.2.2</version>
    </dependency>

    定義http介面

    介面必須使用 @RetrofitClient 註解標記 !http相關註解可參考官方文件:retrofit官方文件。

    @RetrofitClient(baseUrl = "${test.baseUrl}")
    public interface HttpApi {
    @GET("person")
    Result<Person> getPerson(@Query("id") Long id);
    }

    註入使用

    將介面註入到其它Service中即可使用!

    @Service
    public class TestService {
    @Autowired
    private HttpApi httpApi;
    public void test() {
    // 透過httpApi發起http請求
    }
    }

    HTTP請求相關註解

    HTTP 請求相關註解,全部使用了 retrofit 原生註解。 詳細資訊可參考官方文件:retrofit官方文件 ,以下是一個簡單說明。

    註解分類 支持的註解
    請求方式 @GET @HEAD @POST @PUT @DELETE @OPTIONS
    請求頭 @Header @HeaderMap @Headers
    Query參數 @Query @QueryMap @QueryName
    path參數 @Path
    form-encoded參數 @Field @FieldMap @FormUrlEncoded
    檔上傳 @Multipart @Part @PartMap
    url參數 @Url

    配置項說明

    retrofit-spring-boot-starter 支持了多個可配置的內容,用來應對不同的業務場景。您可以視情況進行修改,具體說明如下:

    配置 預設值 說明
    enable-log true 啟用日誌打印
    logging-interceptor DefaultLoggingInterceptor 日誌打印攔截器
    pool 連線池配置
    disable-void-return-type false 禁用java.lang.Void返回型別
    retry-interceptor DefaultRetryInterceptor 請求重試攔截器
    global-converter-factories JacksonConverterFactory 全域轉換器工廠
    global-call-adapter-factories BodyCallAdapterFactory,ResponseCallAdapterFactory 全域呼叫介面卡工廠
    enable-degrade false 是否啟用熔斷降級
    degrade-type sentinel 熔斷降級實作方式(目前僅支持Sentinel)
    resource-name-parser DefaultResourceNameParser 熔斷資源名稱解析器,用於解析資源名稱

    yml 配置方式:

    retrofit:
    enable-response-call-adapter: true
    # 啟用日誌打印
    enable-log: true
    # 連線池配置
    pool:
    test1:
    max-idle-connections: 3
    keep-alive-second: 100
    test2:
    max-idle-connections: 5
    keep-alive-second: 50
    # 禁用void返回值型別
    disable-void-return-type: false
    # 日誌打印攔截器
    logging-interceptor: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultLoggingInterceptor
    # 請求重試攔截器
    retry-interceptor: com.github.lianjiatech.retrofit.spring.boot.retry.DefaultRetryInterceptor
    # 全域轉換器工廠
    global-converter-factories:
    - retrofit2.converter.jackson.JacksonConverterFactory
    # 全域呼叫介面卡工廠
    global-call-adapter-factories:
    - com.github.lianjiatech.retrofit.spring.boot.core.BodyCallAdapterFactory
    - com.github.lianjiatech.retrofit.spring.boot.core.ResponseCallAdapterFactory
    # 是否啟用熔斷降級
    enable-degrade: true
    # 熔斷降級實作方式
    degrade-type: sentinel
    # 熔斷資源名稱解析器
    resource-name-parser: com.github.lianjiatech.retrofit.spring.boot.degrade.DefaultResourceNameParser

    高級功能

    自訂註入OkHttpClient

    通常情況下,透過 @RetrofitClient 註解內容動態建立 OkHttpClient 物件能夠滿足大部份使用場景。但是在某些情況下,使用者可能需要自訂 OkHttpClient ,這個時候,可以在介面上定義返回型別是 OkHttpClient.Builder 的靜態方法來實作。程式碼範例如下:

    @RetrofitClient(baseUrl = "http://ke.com")
    public interface HttpApi3 {
    @OkHttpClientBuilder
    static OkHttpClient.Builder okhttpClientBuilder() {
    return new OkHttpClient.Builder()
    .connectTimeout(1, TimeUnit.SECONDS)
    .readTimeout(1, TimeUnit.SECONDS)
    .writeTimeout(1, TimeUnit.SECONDS);
    }
    @GET
    Result<Person> getPerson(@Url String url, @Query("id") Long id);
    }

    方法必須使用 @OkHttpClientBuilder 註解標記!

    註解式攔截器

    很多時候,我們希望某個介面下的某些http請求執行統一的攔截處理邏輯。為了支持這個功能, retrofit-spring-boot-starter 提供了 註解式攔截器 ,做到了 基於url路徑的匹配攔截 。使用的步驟主要分為2步:

    1. 繼承 BasePathMatchInterceptor 編寫攔截處理器;

    2. 介面上使用 @Intercept 進行標註。如需配置多個攔截器,在介面上標註多個 @Intercept 註解即可!

    下面以 給指定請求的url後面拼接timestamp時間戳 為例,介紹下如何使用註解式攔截器。

    繼承 BasePathMatchInterceptor 編寫攔截處理器

    @Component
    public class TimeStampInterceptor extends BasePathMatchInterceptor {
    @Override
    public Response doIntercept(Chain chain) throws IOException {
    Request request = chain.request();
    HttpUrl url = request.url();
    long timestamp = System.currentTimeMillis();
    HttpUrl newUrl = url.newBuilder()
    .addQueryParameter("timestamp", String.valueOf(timestamp))
    .build();
    Request newRequest = request.newBuilder()
    .url(newUrl)
    .build();
    return chain.proceed(newRequest);
    }
    }

    介面上使用 @Intercept 進行標註

    @RetrofitClient(baseUrl = "${test.baseUrl}")
    @Intercept(handler = TimeStampInterceptor. class, include = {"/api/**"}, exclude = "/api/test/savePerson")
    public interface HttpApi {
    @GET("person")
    Result<Person> getPerson(@Query("id") Long id);
    @POST("savePerson")
    Result<Person> savePerson(@Body Person person);
    }

    上面的 @Intercept 配置表示:攔截 HttpApi 介面下 /api/** 路徑下(排除 /api/test/savePerson )的請求,攔截處理器使用 TimeStampInterceptor

    擴充套件註解式攔截器

    有的時候,我們需要在 攔截註解 動態傳入一些參數,然後再執行攔截的時候需要使用這個參數。這種時候,我們可以擴充套件實作 自訂攔截註解 自訂攔截註解 必須使用 @InterceptMark 標記,並且 註解中必須包括 include()、exclude()、handler() 內容資訊 。使用的步驟主要分為3步:

    1. 自訂攔截註解

    2. 繼承 BasePathMatchInterceptor 編寫攔截處理器

    3. 介面上使用自訂攔截註解;

    例如我們需要 在請求頭裏面動態加入 accessKeyId accessKeySecret 簽名資訊才能正常發起http請求 ,這個時候 可以自訂一個加簽攔截器註解 @Sign 來實作 。下面以自訂 @Sign 攔截註解為例進行說明。

    自訂 @Sign 註解

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @Documented
    @InterceptMark
    public @interface Sign {
    /**
    * 金鑰key
    * 支持占位符形式配置。
    *
    * @return
    */
    String accessKeyId();
    /**
    * 金鑰
    * 支持占位符形式配置。
    *
    * @return
    */
    String accessKeySecret();
    /**
    * 攔截器匹配路徑
    *
    * @return
    */
    String[] include() default {"/**"};
    /**
    * 攔截器排除匹配,排除指定路徑攔截
    *
    * @return
    */
    String[] exclude() default {};
    /**
    * 處理該註解的攔截器類
    * 優先從spring容器獲取對應的Bean,如果獲取不到,則使用反射建立一個!
    *
    * @return
    */
    class<? extends BasePathMatchInterceptor> handler() default SignInterceptor. class;
    }


    擴充套件 自訂攔截註解 有以下2點需要註意:

    1. 自訂攔截註解 必須使用 @InterceptMark 標記。

    2. 註解中必須包括 include()、exclude()、handler() 內容資訊。

    實作 SignInterceptor

    @Component
    public class SignInterceptor extends BasePathMatchInterceptor {
    private String accessKeyId;
    private String accessKeySecret;
    public void setAccessKeyId(String accessKeyId) {
    this.accessKeyId = accessKeyId;
    }
    public void setAccessKeySecret(String accessKeySecret) {
    this.accessKeySecret = accessKeySecret;
    }
    @Override
    public Response doIntercept(Chain chain) throws IOException {
    Request request = chain.request();
    Request newReq = request.newBuilder()
    .addHeader("accessKeyId", accessKeyId)
    .addHeader("accessKeySecret", accessKeySecret)
    .build();
    return chain.proceed(newReq);
    }
    }



    上述 accessKeyId accessKeySecret 欄位值會依據 @Sign 註解的 accessKeyId() accessKeySecret() 值自動註入,如果 @Sign 指定的是占位符形式的字串,則會取配置內容值進行註入 。另外,** accessKeyId accessKeySecret 欄位必須提供 setter 方法** 。

    介面上使用 @Sign

    @RetrofitClient(baseUrl = "${test.baseUrl}")
    @Sign(accessKeyId = "${test.accessKeyId}", accessKeySecret = "${test.accessKeySecret}", exclude = {"/api/test/person"})
    public interface HttpApi {
    @GET("person")
    Result<Person> getPerson(@Query("id") Long id);
    @POST("savePerson")
    Result<Person> savePerson(@Body Person person);
    }

    這樣就能在指定url的請求上,自動加上簽名資訊了。

    連線池管理

    預設情況下,所有透過 Retrofit 發送的http請求都會使用 max-idle-connections=5 keep-alive-second=300 的預設連線池。當然,我們也可以在配置檔中配置多個自訂的連線池,然後透過 @RetrofitClient poolName 內容來指定使用。比如我們要讓某個介面下的請求全部使用 poolName=test1 的連線池,程式碼實作如下:

    1. 配置連線池。

    retrofit:
    # 連線池配置
    pool:
    test1:
    max-idle-connections: 3
    keep-alive-second: 100
    test2:
    max-idle-connections: 5
    keep-alive-second: 50

    1. 透過 @RetrofitClient poolName 內容來指定使用的連線池。

    @RetrofitClient(baseUrl = "${test.baseUrl}", poolName="test1")
    public interface HttpApi {
    @GET("person")
    Result<Person> getPerson(@Query("id") Long id);
    }

    日誌打印

    很多情況下,我們希望將http請求日誌記錄下來。透過 retrofit.enableLog 配置可以全域控制日誌是否開啟。針對每個介面,可以透過 @RetrofitClient enableLog 控制是否開啟,透過 logLevel logStrategy ,可以指定每個介面的日誌打印級別以及日誌打印策略。 retrofit-spring-boot-starter 支持了5種日誌打印級別( ERROR , WARN , INFO , DEBUG , TRACE ),預設 INFO ;支持了4種日誌打印策略( NONE , BASIC , HEADERS , BODY ),預設 BASIC 。4種日誌打印策略含義如下:

    1. NONE :No logs.

    2. BASIC :Logs request and response lines.

    3. HEADERS :Logs request and response lines and their respective headers.

    4. BODY :Logs request and response lines and their respective headers and bodies (if present).

    retrofit-spring-boot-starter 預設使用了 DefaultLoggingInterceptor 執行真正的日誌打印功能,其底層就是 okhttp 原生的 HttpLoggingInterceptor 。當然,你也可以自訂實作自己的日誌打印攔截器,只需要繼承 BaseLoggingInterceptor (具體可以參考 DefaultLoggingInterceptor 的實作),然後在配置檔中進行相關配置即可。

    retrofit:
    # 日誌打印攔截器
    logging-interceptor: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultLoggingInterceptor

    請求重試

    retrofit-spring-boot-starter 支持請求重試功能,只需要在介面或者方法上加上 @Retry 註解即可。** @Retry 支持重試次數 maxRetries 、重試時間間隔 intervalMs 以及重試規則 retryRules 配置** 。重試規則支持三種配置:

    1. RESPONSE_STATUS_NOT_2XX :響應狀態碼不是 2xx 時執行重試;

    2. OCCUR_IO_EXCEPTION :發生IO異常時執行重試;

    3. OCCUR_EXCEPTION :發生任意異常時執行重試;

    預設響應狀態碼不是 2xx 或者發生IO異常時自動進行重試。需要的話,你也可以繼承 BaseRetryInterceptor 實作自己的請求重試攔截器,然後將其配置上去。

    retrofit:
    # 請求重試攔截器
    retry-interceptor: com.github.lianjiatech.retrofit.spring.boot.retry.DefaultRetryInterceptor

    錯誤解碼器

    HTTP 發生請求錯誤(包括發生異常或者響應數據不符合預期)的時候,錯誤解碼器可將 HTTP 相關資訊解碼到自訂異常中。你可以在 @RetrofitClient 註解的 errorDecoder() 指定當前介面的錯誤解碼器,自訂錯誤解碼器需要實作 ErrorDecoder 介面:

    /**
     * 錯誤解碼器。ErrorDecoder.
     * 當請求發生異常或者收到無效響應結果的時候,將HTTP相關資訊解碼到異常中,無效響應由業務自己判斷
     *
     * When an exception occurs in the request or an invalid response result is received, the HTTP related information is decoded into the exception,
     * and the invalid response is determined by the business itself.
     *
     * @author 陳添明
     */
    public interface ErrorDecoder {
    /**
    * 當無效響應的時候,將HTTP資訊解碼到異常中,無效響應由業務自行判斷。
    * When the response is invalid, decode the HTTP information into the exception, invalid response is determined by business.
    *
    * @param request request
    * @param response response
    * @return If it returns null, the processing is ignored and the processing continues with the original response.
    */
    default RuntimeException invalidRespDecode(Request request, Response response) {
    if (!response.isSuccessful()) {
    throw RetrofitException.errorStatus(request, response);
    }
    return null;
    }

    /**
    * 當請求發生IO異常時,將HTTP資訊解碼到異常中。
    * When an IO exception occurs in the request, the HTTP information is decoded into the exception.
    *
    * @param request request
    * @param cause IOException
    * @return RuntimeException
    */
    default RuntimeException ioExceptionDecode(Request request, IOException cause) {
    return RetrofitException.errorExecuting(request, cause);
    }
    /**
    * 當請求發生除IO異常之外的其它異常時,將HTTP資訊解碼到異常中。
    * When the request has an exception other than the IO exception, the HTTP information is decoded into the exception.
    *
    * @param request request
    * @param cause Exception
    * @return RuntimeException
    */
    default RuntimeException exceptionDecode(Request request, Exception cause) {
    return RetrofitException.errorUnknown(request, cause);
    }
    }


    全域攔截器

    全域套用攔截器

    如果我們需要對整個系統的的http請求執行統一的攔截處理,可以自訂實作全域攔截器 BaseGlobalInterceptor , 並配置成 spring 容器中的 bean !例如我們需要在整個系統發起的http請求,都帶上來源資訊。

    @Component
    public class SourceInterceptor extends BaseGlobalInterceptor {
    @Override
    public Response doIntercept(Chain chain) throws IOException {
    Request request = chain.request();
    Request newReq = request.newBuilder()
    .addHeader("source""test")
    .build();
    return chain.proceed(newReq);
    }
    }

    全域網路攔截器

    只需要實作 NetworkInterceptor 介面 並配置成 spring 容器中的 bean 就支持自動織入全域網路攔截器。

    熔斷降級

    在分布式服務架構中,對不穩定的外部服務進行熔斷降級是保證服務高可用的重要措施之一。由於外部服務的穩定性是不能保證的,當外部服務不穩定時,響應時間會變長。相應地,呼叫方的響應時間也會變長,執行緒會產生堆積,最終可能耗盡呼叫方的執行緒池,導致整個服務不可用。因此我們需要對不穩定的弱依賴服務呼叫進行熔斷降級,暫時切斷不穩定呼叫,避免局部不穩定導致整體服務雪崩。

    retrofit-spring-boot-starter 支持熔斷降級功能,底層基於Sentinel實作。具體來說,支持了 熔斷資源自發現 註解式降級規則配置 。如需使用熔斷降級,只需要進行以下操作即可:

    1. 開啟熔斷降級功能

    預設情況下,熔斷降級功能是關閉的,需要設定相應的配置項來開啟熔斷降級功能

    retrofit:
    # 是否啟用熔斷降級
    enable-degrade: true
    # 熔斷降級實作方式(目前僅支持Sentinel)
    degrade-type: sentinel
    # 資源名稱解析器
    resource-name-parser: com.github.lianjiatech.retrofit.spring.boot.degrade.DefaultResourceNameParser

    資源名稱解析器用於實作使用者自訂資源名稱,預設配置是 DefaultResourceNameParser ,對應的資源名稱格式為 HTTP_OUT:GET:http://localhost:8080/api/degrade/test 。使用者可以繼承 BaseResourceNameParser 類實作自己的資源名稱解析器。

    另外,由於熔斷降級功能是可選的, 因此啟用熔斷降級需要使用者自行引入Sentinel依賴

    <dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-core</artifactId>
    <version>1.6.3</version>
    </dependency>

    2. 配置降級規則(可選)

    retrofit-spring-boot-starter 支持註解式配置降級規則,透過 @Degrade 註解來配置降級規則 @Degrade 註解可以配置在介面或者方法上,配置在方法上的優先級更高。

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Documented
    public @interface Degrade {
    /**
    * RT threshold or exception ratio threshold count.
    */
    double count();
    /**
    * Degrade recover timeout (in seconds) when degradation occurs.
    */
    int timeWindow() default 5;
    /**
    * Degrade strategy (0: average RT, 1: exception ratio).
    */
    DegradeStrategy degradeStrategy() default DegradeStrategy.AVERAGE_RT;
    }

    如果套用計畫已支持透過配置中心配置降級規則,可忽略註解式配置方式

    3. @RetrofitClient設定fallback或者fallbackFactory (可選)

    如果 @RetrofitClient 不設定 fallback 或者 fallbackFactory ,當觸發熔斷時,會直接丟擲 RetrofitBlockException 異常。 使用者可以透過設定 fallback 或者 fallbackFactory 來客製熔斷時的方法返回值 fallback 類必須是當前介面的實作類, fallbackFactory 必須是 FallbackFactory<T> 實作類,泛型參數型別為當前介面型別。另外, fallback fallbackFactory 例項必須配置成 Spring 容器的 Bean

    fallbackFactory 相對於 fallback ,主要差別在於能夠感知每次熔斷的異常原因(cause) 。參考範例如下:

    @Slf4j
    @Service
    public class HttpDegradeFallback implements HttpDegradeApi {
    @Override
    public Result<Integer> test() {
    Result<Integer> fallback = new Result<>();
    fallback.setCode(100)
    .setMsg("fallback")
    .setBody(1000000);
    return fallback;
    }
    }
    @Slf4j
    @Service
    public class HttpDegradeFallbackFactory implements FallbackFactory<HttpDegradeApi> {
    /**
    * Returns an instance of the fallback appropriate for the given cause
    *
    * @param cause fallback cause
    * @return 實作了retrofit介面的例項。an instance that implements the retrofit interface.
    */
    @Override
    public HttpDegradeApi create(Throwable cause) {
    log.error("觸發熔斷了! ", cause.getMessage(), cause);
    return new HttpDegradeApi() {
    @Override
    public Result<Integer> test() {
    Result<Integer> fallback = new Result<>();
    fallback.setCode(100)
    .setMsg("fallback")
    .setBody(1000000);
    return fallback;
    }
    }
    }

    微服務之間的HTTP呼叫

    為了能夠使用微服務呼叫,需要進行如下配置:

    配置 ServiceInstanceChooser Spring 容器 Bean

    使用者可以自行實作 ServiceInstanceChooser 介面,完成服務例項的選取邏輯,並將其配置成 Spring 容器的 Bean 。對於 Spring Cloud 套用, retrofit-spring-boot-starter 提供了 SpringCloudServiceInstanceChooser 實作,使用者只需將其配置成 Spring Bean 即可。

    @Bean
    @Autowired
    public ServiceInstanceChooser serviceInstanceChooser(LoadBalancerClient loadBalancerClient) {
    return new SpringCloudServiceInstanceChooser(loadBalancerClient);
    }

    使用 @Retrofit serviceId path 內容,可以實作微服務之間的HTTP呼叫

    @RetrofitClient(serviceId = "${jy-helicarrier-api.serviceId}", path = "/m/count", errorDecoder = HelicarrierErrorDecoder. class)
    @Retry
    public interface ApiCountService {
    }

    呼叫介面卡和數據轉碼器

    呼叫介面卡

    Retrofit 可以透過呼叫介面卡 CallAdapterFactory Call<T> 物件適配成介面方法的返回值型別。 retrofit-spring-boot-starter 擴充套件2種 CallAdapterFactory 實作:

    BodyCallAdapterFactory

  • 預設啟用,可透過配置 retrofit.enable-body-call-adapter=false 關閉

  • 同步執行http請求,將響應體內容適配成介面方法的返回值型別例項。

  • 除了 Retrofit.Call<T> Retrofit.Response<T> java.util.concurrent.CompletableFuture<T> 之外,其它返回型別都可以使用該介面卡。

  •  ResponseCallAdapterFactory

  • 預設啟用,可透過配置 retrofit.enable-response-call-adapter=false 關閉

  • 同步執行http請求,將響應體內容適配成 Retrofit.Response<T> 返回。

  • 如果方法的返回值型別為 Retrofit.Response<T> ,則可以使用該介面卡。

  • Retrofit自動根據方法返回值型別選用對應的 CallAdapterFactory 執行適配處理!加上Retrofit預設的 CallAdapterFactory ,可支持多種形式的方法返回值型別:

  • Call<T> : 不執行適配處理,直接返回 Call<T> 物件

  • CompletableFuture<T> : 將響應體內容適配成 CompletableFuture<T> 物件返回

  • Void : 不關註返回型別可以使用 Void 。如果http狀態碼不是2xx,直接拋錯!

  • Response<T> : 將響應內容適配成 Response<T> 物件返回

  • 其他任意Java型別:將響應體內容適配成一個對應的Java型別物件返回,如果http狀態碼不是2xx,直接拋錯!

  • /**
    * Call<T>
    * 不執行適配處理,直接返回Call<T>物件
    * @param id
    * @return
    */
    @GET("person")
    Call<Result<Person>> getPersonCall(@Query("id") Long id);
    /**
    * CompletableFuture<T>
    * 將響應體內容適配成CompletableFuture<T>物件返回
    * @param id
    * @return
    */
    @GET("person")
    CompletableFuture<Result<Person>> getPersonCompletableFuture(@Query("id") Long id);
    /**
    * Void
    * 不關註返回型別可以使用Void。如果http狀態碼不是2xx,直接拋錯!
    * @param id
    * @return
    */
    @GET("person")
    Void getPersonVoid(@Query("id") Long id);
    /**
    * Response<T>
    * 將響應內容適配成Response<T>物件返回
    * @param id
    * @return
    */
    @GET("person")
    Response<Result<Person>> getPersonResponse(@Query("id") Long id);
    /**
    * 其他任意Java型別
    * 將響應體內容適配成一個對應的Java型別物件返回,如果http狀態碼不是2xx,直接拋錯!
    * @param id
    * @return
    */
    @GET("person")
    Result<Person> getPerson(@Query("id") Long id);


    我們也可以透過繼承 CallAdapter.Factory 擴充套件實作自己的 CallAdapter

    retrofit-spring-boot-starter 支持透過 retrofit.global-call-adapter-factories 配置全域呼叫介面卡工廠,工廠例項優先從Spring容器獲取,如果沒有獲取到,則反射建立。預設的全域呼叫介面卡工廠是 [BodyCallAdapterFactory, ResponseCallAdapterFactory]

    retrofit:
    # 全域呼叫介面卡工廠
    global-call-adapter-factories:
    - com.github.lianjiatech.retrofit.spring.boot.core.BodyCallAdapterFactory
    - com.github.lianjiatech.retrofit.spring.boot.core.ResponseCallAdapterFactory

    針對每個Java介面,還可以透過 @RetrofitClient 註解的 callAdapterFactories() 指定當前介面采用的 CallAdapter.Factory ,指定的工廠例項依然優先從Spring容器獲取。

    註意:如果 CallAdapter.Factory 沒有 public 的無參構造器,請手動將其配置成 Spring 容器的 Bean 物件

    數據轉碼器

    Retrofit 使用 Converter @Body 註解標註的物件轉換成請求體,將響應體數據轉換成一個 Java 物件,可以選用以下幾種 Converter

  • Gson: com.squareup.Retrofit:converter-gson

  • Jackson: com.squareup.Retrofit:converter-jackson

  • Moshi: com.squareup.Retrofit:converter-moshi

  • Protobuf: com.squareup.Retrofit:converter-protobuf

  • Wire: com.squareup.Retrofit:converter-wire

  • Simple XML: com.squareup.Retrofit:converter-simplexml

  • JAXB: com.squareup.retrofit2:converter-jaxb

  • retrofit-spring-boot-starter 支持透過 retrofit.global-converter-factories 配置全域數據轉換器工廠,轉換器工廠例項優先從Spring容器獲取,如果沒有獲取到,則反射建立。預設的全域數據轉換器工廠是 retrofit2.converter.jackson.JacksonConverterFactory ,你可以直接透過 spring.jackson.* 配置 jackson 序列化規則,配置可參考Customize the Jackson ObjectMapper!

    retrofit:
    # 全域轉換器工廠
    global-converter-factories:
    - retrofit2.converter.jackson.JacksonConverterFactory

    針對每個Java介面,還可以透過 @RetrofitClient 註解的 converterFactories() 指定當前介面采用的 Converter.Factory ,指定的轉換器工廠例項依然優先從Spring容器獲取。

    註意:如果 Converter.Factory 沒有 public 的無參構造器,請手動將其配置成 Spring 容器的 Bean 物件

    總結

    retrofit-spring-boot-starter 一個適用於 SpringBoot 計畫的輕量級 HTTP 客戶端框架,已線上上穩定執行一年多,並且已經有多個外部公司也接入使用。

    >>

    END

    精品資料,超贊福利,免費領

    微信掃碼/長按辨識 添加【技術交流群

    群內每天分享精品學習資料

    最近開發整理了一個用於速刷面試題的小程式;其中收錄了上千道常見面試題及答案(包含基礎並行JVMMySQLRedisSpringSpringMVCSpringBootSpringCloud訊息佇列等多個型別),歡迎您的使用。

    👇👇

    👇點選"閱讀原文",獲取更多資料(持續更新中