1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        扔掉okhttp、httpClient,來試試這款輕量級HTTP客戶端神器?

        共 5152字,需瀏覽 11分鐘

         ·

        2020-12-23 10:30



        SpringBoot項目直接使用okhttp、httpClient或者RestTemplate發(fā)起HTTP請求,既繁瑣又不方便統(tǒng)一管理。因此,在這里推薦一個適用于SpringBoot項目的輕量級HTTP客戶端框架retrofit-spring-boot-starter,使用非常簡單方便,同時又提供諸多功能增強。目前項目已經(jīng)更新至2.2.2版本,并且會持續(xù)進行迭代優(yōu)化。

        github項目地址:

        https://github.com/LianjiaTech/retrofit-spring-boot-starter

        gitee項目地址:

        https://gitee.com/lianjiatech/retrofit-spring-boot-starter

        前言

        Retrofit是適用于AndroidJava且類型安全的HTTP客戶端,其最大的特性的是支持通過接口的方式發(fā)起HTTP請求。而spring-boot是使用最廣泛的Java開發(fā)框架,但是Retrofit官方?jīng)]有支持與spring-boot框架快速整合,因此我們開發(fā)了retrofit-spring-boot-starter。

        retrofit-spring-boot-starter實現(xiàn)了Retrofitspring-boot框架快速整合,并且支持了諸多功能增強,極大簡化開發(fā)。

        功能特性

        • 自定義注入OkHttpClient
        • 注解式攔截器
        • 連接池管理
        • 日志打印
        • 請求重試
        • 錯誤解碼器
        • 全局攔截器
        • 熔斷降級
        • 微服務之間的HTTP調(diào)用
        • 調(diào)用適配器
        • 數(shù)據(jù)轉換器

        快速使用

        引入依賴


        ????com.github.lianjiatech
        ????retrofit-spring-boot-starter
        ????2.2.2

        定義http接口

        接口必須使用@RetrofitClient注解標記!http相關注解可參考官方文檔:retrofit官方文檔。搜索Java核心技術,回復“888”,送你一份Java面試題寶典.pdf

        https://square.github.io/retrofit/

        @RetrofitClient(baseUrl?=?"${test.baseUrl}")
        public?interface?HttpApi?{

        ????@GET("person")
        ????Result?getPerson(@Query("id")?Long?id);
        }

        注入使用

        將接口注入到其它Service中即可使用!

        @Service
        public?class?TestService?{

        ????@Autowired
        ????private?HttpApi?httpApi;

        ????public?void?test()?{
        ????????//?通過httpApi發(fā)起http請求
        ????}
        }

        HTTP請求相關注解

        HTTP請求相關注解,全部使用了retrofit原生注解。詳細信息可參考官方文檔,以下是一個簡單說明。

        img

        配置項說明

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


        img

        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
        ??#?全局調(diào)用適配器工廠
        ??global-call-adapter-factories:
        ????-?com.github.lianjiatech.retrofit.spring.boot.core.BodyCallAdapterFactory
        ????-?com.github.lianjiatech.retrofit.spring.boot.core.ResponseCallAdapterFactory
        ??#?是否啟用熔斷降級
        ??enable-degrade:?true
        ??#?熔斷降級實現(xiàn)方式
        ??degrade-type:?sentinel
        ??#?熔斷資源名稱解析器
        ??resource-name-parser:?com.github.lianjiatech.retrofit.spring.boot.degrade.DefaultResourceNameParser

        高級功能

        自定義注入OkHttpClient

        通常情況下,通過@RetrofitClient注解屬性動態(tài)創(chuàng)建OkHttpClient對象能夠滿足大部分使用場景。但是在某些情況下,用戶可能需要自定義OkHttpClient,這個時候,可以在接口上定義返回類型是OkHttpClient.Builder的靜態(tài)方法來實現(xiàn)。代碼示例如下:

        @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?getPerson(@Url?String?url,?@Query("id")?Long?id);
        }

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

        注解式攔截器

        很多時候,我們希望某個接口下的某些http請求執(zhí)行統(tǒng)一的攔截處理邏輯。為了支持這個功能,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?getPerson(@Query("id")?Long?id);

        ????@POST("savePerson")
        ????Result?savePerson(@Body?Person?person);
        }

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

        擴展注解式攔截器

        有的時候,我們需要在攔截注解動態(tài)傳入一些參數(shù),然后再執(zhí)行攔截的時候需要使用這個參數(shù)。這種時候,我們可以擴展實現(xiàn)自定義攔截注解自定義攔截注解必須使用@InterceptMark標記,并且注解中必須包括include()、exclude()、handler()屬性信息。使用的步驟主要分為3步:

        1. 自定義攔截注解
        2. 繼承BasePathMatchInterceptor編寫攔截處理器
        3. 接口上使用自定義攔截注解;

        例如我們需要在請求頭里面動態(tài)加入accessKeyIdaccessKeySecret簽名信息才能正常發(fā)起http請求,這個時候可以自定義一個加簽攔截器注解@Sign來實現(xiàn)。下面以自定義@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?{};

        ????/**
        ?????*?處理該注解的攔截器類
        ?????*?優(yōu)先從spring容器獲取對應的Bean,如果獲取不到,則使用反射創(chuàng)建一個!
        ?????*
        ?????*?@return
        ?????*/
        ????Class?handler()?default?SignInterceptor.class;
        }

        擴展自定義攔截注解有以下2點需要注意:

        1. 自定義攔截注解必須使用@InterceptMark標記。
        2. 注解中必須包括include()、exclude()、handler()屬性信息。

        實現(xiàn)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);
        ????}
        }

        上述accessKeyIdaccessKeySecret字段值會依據(jù)@Sign注解的accessKeyId()accessKeySecret()值自動注入,如果@Sign指定的是占位符形式的字符串,則會取配置屬性值進行注入。另外,accessKeyIdaccessKeySecret字段必須提供setter方法。

        接口上使用@Sign

        @RetrofitClient(baseUrl?=?"${test.baseUrl}")
        @Sign(accessKeyId?=?"${test.accessKeyId}",?accessKeySecret?=?"${test.accessKeySecret}",?exclude?=?{"/api/test/person"})
        public?interface?HttpApi?{

        ????@GET("person")
        ????Result?getPerson(@Query("id")?Long?id);

        ????@POST("savePerson")
        ????Result?savePerson(@Body?Person?person);
        }

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

        連接池管理

        默認情況下,所有通過Retrofit發(fā)送的http請求都會使用max-idle-connections=5 keep-alive-second=300的默認連接池。當然,我們也可以在配置文件中配置多個自定義的連接池,然后通過@RetrofitClientpoolName屬性來指定使用。比如我們要讓某個接口下的請求全部使用poolName=test1的連接池,代碼實現(xiàn)如下:

        1. 配置連接池。
        retrofit:
        ????#?連接池配置
        ????pool:
        ????????test1:
        ????????max-idle-connections:?3
        ????????keep-alive-second:?100
        ????????test2:
        ????????max-idle-connections:?5
        ????????keep-alive-second:?50
        1. 通過@RetrofitClientpoolName屬性來指定使用的連接池。
        @RetrofitClient(baseUrl?=?"${test.baseUrl}",?poolName="test1")
        public?interface?HttpApi?{

        ????@GET("person")
        ????Result?getPerson(@Query("id")?Long?id);
        }

        日志打印

        很多情況下,我們希望將http請求日志記錄下來。通過retrofit.enableLog配置可以全局控制日志是否開啟。針對每個接口,可以通過@RetrofitClientenableLog控制是否開啟,通過logLevellogStrategy,可以指定每個接口的日志打印級別以及日志打印策略。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執(zhí)行真正的日志打印功能,其底層就是okhttp原生的HttpLoggingInterceptor。當然,你也可以自定義實現(xiàn)自己的日志打印攔截器,只需要繼承BaseLoggingInterceptor(具體可以參考DefaultLoggingInterceptor的實現(xiàn)),然后在配置文件中進行相關配置即可。

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

        請求重試

        retrofit-spring-boot-starter支持請求重試功能,只需要在接口或者方法上加上@Retry注解即可。@Retry支持重試次數(shù)maxRetries、重試時間間隔intervalMs以及重試規(guī)則retryRules配置。重試規(guī)則支持三種配置:

        1. RESPONSE_STATUS_NOT_2XX:響應狀態(tài)碼不是2xx時執(zhí)行重試;
        2. OCCUR_IO_EXCEPTION:發(fā)生IO異常時執(zhí)行重試;
        3. OCCUR_EXCEPTION:發(fā)生任意異常時執(zhí)行重試;

        默認響應狀態(tài)碼不是2xx或者發(fā)生IO異常時自動進行重試。需要的話,你也可以繼承BaseRetryInterceptor實現(xiàn)自己的請求重試攔截器,然后將其配置上去。

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

        錯誤解碼器

        HTTP發(fā)生請求錯誤(包括發(fā)生異?;蛘唔憫獢?shù)據(jù)不符合預期)的時候,錯誤解碼器可將HTTP相關信息解碼到自定義異常中。你可以在@RetrofitClient注解的errorDecoder()指定當前接口的錯誤解碼器,自定義錯誤解碼器需要實現(xiàn)ErrorDecoder接口:

        /**
        ?*?錯誤解碼器。ErrorDecoder.
        ?*?當請求發(fā)生異?;蛘呤盏綗o效響應結果的時候,將HTTP相關信息解碼到異常中,無效響應由業(yè)務自己判斷
        ?*
        ?*?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信息解碼到異常中,無效響應由業(yè)務自行判斷。
        ?????*?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;
        ????}


        ????/**
        ?????*?當請求發(fā)生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);
        ????}

        ????/**
        ?????*?當請求發(fā)生除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);
        ????}

        }

        全局攔截器

        全局應用攔截器

        如果我們需要對整個系統(tǒng)的的http請求執(zhí)行統(tǒng)一的攔截處理,可以自定義實現(xiàn)全局攔截器BaseGlobalInterceptor, 并配置成spring容器中的bean!例如我們需要在整個系統(tǒng)發(fā)起的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);
        ????}
        }

        全局網(wǎng)絡攔截器

        只需要實現(xiàn)NetworkInterceptor接口 并配置成spring容器中的bean就支持自動織入全局網(wǎng)絡攔截器。

        熔斷降級

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

        retrofit-spring-boot-starter支持熔斷降級功能,底層基于Sentinel實現(xiàn)。具體來說,支持了熔斷資源自發(fā)現(xiàn)注解式降級規(guī)則配置。如需使用熔斷降級,只需要進行以下操作即可:

        1. 開啟熔斷降級功能

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

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

        資源名稱解析器用于實現(xiàn)用戶自定義資源名稱,默認配置是DefaultResourceNameParser,對應的資源名稱格式為HTTP_OUT:GET:http://localhost:8080/api/degrade/test。用戶可以繼承BaseResourceNameParser類實現(xiàn)自己的資源名稱解析器。

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


        ????com.alibaba.csp
        ????sentinel-core
        ????1.6.3

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

        retrofit-spring-boot-starter支持注解式配置降級規(guī)則,通過@Degrade注解來配置降級規(guī)則。@Degrade注解可以配置在接口或者方法上,配置在方法上的優(yōu)先級更高。

        @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;
        }

        如果應用項目已支持通過配置中心配置降級規(guī)則,可忽略注解式配置方式。

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

        如果@RetrofitClient不設置fallback或者fallbackFactory,當觸發(fā)熔斷時,會直接拋出RetrofitBlockException異常。用戶可以通過設置fallback或者fallbackFactory來定制熔斷時的方法返回值。fallback類必須是當前接口的實現(xiàn)類,fallbackFactory必須是FallbackFactory實現(xiàn)類,泛型參數(shù)類型為當前接口類型。另外,fallbackfallbackFactory實例必須配置成Spring容器的Bean。

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

        @Slf4j
        @Service
        public?class?HttpDegradeFallback?implements?HttpDegradeApi?{

        ????@Override
        ????public?Result?test()?{
        ????????Result?fallback?=?new?Result<>();
        ????????fallback.setCode(100)
        ????????????????.setMsg("fallback")
        ????????????????.setBody(1000000);
        ????????return?fallback;
        ????}
        }
        @Slf4j
        @Service
        public?class?HttpDegradeFallbackFactory?implements?FallbackFactory?{

        ????/**
        ?????*?Returns?an?instance?of?the?fallback?appropriate?for?the?given?cause
        ?????*
        ?????*?@param?cause?fallback?cause
        ?????*?@return?實現(xiàn)了retrofit接口的實例。an instance that implements the retrofit interface.
        ?????*/
        ????@Override
        ????public?HttpDegradeApi?create(Throwable?cause)?{
        ????????log.error("觸發(fā)熔斷了!?",?cause.getMessage(),?cause);
        ????????return?new?HttpDegradeApi()?{
        ????????????@Override
        ????????????public?Result?test()?{
        ????????????????Result?fallback?=?new?Result<>();
        ????????????????fallback.setCode(100)
        ????????????????????????.setMsg("fallback")
        ????????????????????????.setBody(1000000);
        ????????????????return?fallback;
        ????????????}
        ????}
        }

        微服務之間的HTTP調(diào)用

        為了能夠使用微服務調(diào)用,需要進行如下配置:

        配置ServiceInstanceChooserSpring容器Bean

        用戶可以自行實現(xiàn)ServiceInstanceChooser接口,完成服務實例的選取邏輯,并將其配置成Spring容器的Bean。對于Spring Cloud應用,retrofit-spring-boot-starter提供了SpringCloudServiceInstanceChooser實現(xiàn),用戶只需將其配置成SpringBean即可。

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

        使用@RetrofitserviceIdpath屬性,可以實現(xiàn)微服務之間的HTTP調(diào)用

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

        }

        調(diào)用適配器和數(shù)據(jù)轉碼器

        調(diào)用適配器

        Retrofit可以通過調(diào)用適配器CallAdapterFactoryCall對象適配成接口方法的返回值類型。retrofit-spring-boot-starter擴展2種CallAdapterFactory實現(xiàn):

        1. BodyCallAdapterFactory
        • 默認啟用,可通過配置retrofit.enable-body-call-adapter=false關閉
        • 同步執(zhí)行http請求,將響應體內(nèi)容適配成接口方法的返回值類型實例。
        • 除了Retrofit.Call、Retrofit.Response、java.util.concurrent.CompletableFuture之外,其它返回類型都可以使用該適配器。
        1. ResponseCallAdapterFactory
        • 默認啟用,可通過配置retrofit.enable-response-call-adapter=false關閉
        • 同步執(zhí)行http請求,將響應體內(nèi)容適配成Retrofit.Response返回。
        • 如果方法的返回值類型為Retrofit.Response,則可以使用該適配器。

        Retrofit自動根據(jù)方法返回值類型選用對應的CallAdapterFactory執(zhí)行適配處理!加上Retrofit默認的CallAdapterFactory,可支持多種形式的方法返回值類型:

        • Call: 不執(zhí)行適配處理,直接返回Call對象
        • CompletableFuture: 將響應體內(nèi)容適配成CompletableFuture對象返回
        • Void: 不關注返回類型可以使用Void。如果http狀態(tài)碼不是2xx,直接拋錯!
        • Response: 將響應內(nèi)容適配成Response對象返回
        • 其他任意Java類型:將響應體內(nèi)容適配成一個對應的Java類型對象返回,如果http狀態(tài)碼不是2xx,直接拋錯!
        ????/**
        ?????*?Call
        ?????*?不執(zhí)行適配處理,直接返回Call對象
        ?????*?@param?id
        ?????*?@return
        ?????*/
        ????@GET("person")
        ????Call>?getPersonCall(@Query("id")?Long?id);

        ????/**
        ?????*??CompletableFuture
        ?????*??將響應體內(nèi)容適配成CompletableFuture對象返回
        ?????*?@param?id
        ?????*?@return
        ?????*/
        ????@GET("person")
        ????CompletableFuture>?getPersonCompletableFuture(@Query("id")?Long?id);

        ????/**
        ?????*?Void
        ?????*?不關注返回類型可以使用Void。如果http狀態(tài)碼不是2xx,直接拋錯!
        ?????*?@param?id
        ?????*?@return
        ?????*/
        ????@GET("person")
        ????Void?getPersonVoid(@Query("id")?Long?id);

        ????/**
        ?????*??Response
        ?????*??將響應內(nèi)容適配成Response對象返回
        ?????*?@param?id
        ?????*?@return
        ?????*/
        ????@GET("person")
        ????Response>?getPersonResponse(@Query("id")?Long?id);

        ????/**
        ?????*?其他任意Java類型
        ?????*?將響應體內(nèi)容適配成一個對應的Java類型對象返回,如果http狀態(tài)碼不是2xx,直接拋錯!
        ?????*?@param?id
        ?????*?@return
        ?????*/
        ????@GET("person")
        ????Result?getPerson(@Query("id")?Long?id);

        我們也可以通過繼承CallAdapter.Factory擴展實現(xiàn)自己的CallAdapter!

        retrofit-spring-boot-starter支持通過retrofit.global-call-adapter-factories配置全局調(diào)用適配器工廠,工廠實例優(yōu)先從Spring容器獲取,如果沒有獲取到,則反射創(chuàng)建。默認的全局調(diào)用適配器工廠是[BodyCallAdapterFactory, ResponseCallAdapterFactory]!

        retrofit:
        ??#?全局調(diào)用適配器工廠
        ??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,指定的工廠實例依然優(yōu)先從Spring容器獲取。

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

        數(shù)據(jù)轉碼器

        Retrofit使用Converter@Body注解標注的對象轉換成請求體,將響應體數(shù)據(jù)轉換成一個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配置全局數(shù)據(jù)轉換器工廠,轉換器工廠實例優(yōu)先從Spring容器獲取,如果沒有獲取到,則反射創(chuàng)建。默認的全局數(shù)據(jù)轉換器工廠是retrofit2.converter.jackson.JacksonConverterFactory,你可以直接通過spring.jackson.*配置jackson序列化規(guī)則,配置可參考:Customize the Jackson ObjectMapper

        https://docs.spring.io/spring-boot/docs/2.1.5.RELEASE/reference/htmlsingle/#howto-customize-the-jackson-objectmapper

        retrofit:
        ??#?全局調(diào)用適配器工廠
        ??global-call-adapter-factories:
        ????-?com.github.lianjiatech.retrofit.spring.boot.core.BodyCallAdapterFactory
        ????-?com.github.lianjiatech.retrofit.spring.boot.core.ResponseCallAdapterFactory

        針對每個Java接口,還可以通過@RetrofitClient注解的converterFactories()指定當前接口采用的Converter.Factory,指定的轉換器工廠實例依然優(yōu)先從Spring容器獲取。

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

        總結

        retrofit-spring-boot-starter一個適用于SpringBoot項目的輕量級HTTP客戶端框架,已在線上穩(wěn)定運行一年多,并且已經(jīng)有多個外部公司也接入使用。有興趣的朋友可以嘗試一下

        作者:伍陸七?
        來源:juejin.cn/post/6898485806587969544

        題外話:推薦一個GitHub項目,這個 GitHub 整理了上百本常用技術PDF,絕大部分核心的技術書籍都可以在這里找到,GitHub地址:https://github.com/gsjqwyl/awesome-ebook(電腦打開體驗更好),地址閱讀原文直達。麻煩打個給個Star,持續(xù)更新中...


        ---END---

        文末福利





        瀏覽 73
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            日本AⅤ在线| 国产精品一级a毛视频| 淫香欲色| 成人二区三区| Al激情欧美| 黄色视频在线免费看| 天堂精品| 中文字幕永久免费| 成人91看片| 亚洲欧美日韩一区二区| 黄色成人网站在线观看免费| 久久久夜夜夜| 狠狠干天天日| 日本成人黄色电影| 成人无码国产| 91丨九色丨老熟女探花| 福利导航视频| 欧美被操| av在线无码观看| 51嘿嘿嘿国产精品伦理| 2019中文字幕mv第三季歌词| 亚洲色图一区二区| 密臀福利导航| 欧美老女人操逼群| 开心激情网站| 色999网址| 蜜臀久久99精品久久久久久牛牛| 爱爱网址| 高清无码黄片| 亚洲一级二级三级| 丁香五月在线视频| 97成人视频| 强伦轩农村人妻| 久久逼逼| 成人网站视频在线观看| 日屄视频在线观看| 日韩欧美黄色| 黄色成人网站在线免费观看| 黄片大全在线观看| 欧美亚洲| 成人啪啪视频| 一区二区无码在线| 无码专区一区二区三区| 日韩成人无码一区二区| 四虎视频| 成人在线视频网站| 黄色成人在线| 一区视频| 毛片网| 色婷婷视频在线观看| 尤物视频在线播放| 东京热视频在线观看| 日韩18禁| 亚洲免费网站| 免费黄色网址啊不卡| 免费射精一二三区| 最新福利视频| 久久亚洲福利视频| 日韩无码人妻一区二区三区| 1024黄| 日韩黄色免费视频| 青草久在线| 午夜福利电影无码| 97精品人妻麻豆一区二区| 国产91探花| 乱伦91视频| 国产欧美第一页| 无码高清视频在线观看| 91在线观看网站| 蜜芽成人精品久久久视频| 艹逼91| 精品码A片18| 四虎成人电影| av中文字幕无码| 亚洲激情一区| A级黄色电影| 青青草视频| 中国老熟女重囗味HDXX| 大香焦久久| 日本黄色免费| 国产综合久久| 久久久久久久久久久久久久久久久久久久| 日韩无码高清视频| 久久永久免费精品人妻专区| 美女插插| 日韩电影免费在线观看| 国产91页| 亚欧黄色| 亚洲熟妇AV日韩熟妇在线| 欧美激情四射| www.丁香五月| 91探花秘在线播放偷拍| 被黑人猛躁10次高潮视频| 草久影院| 国产免费操逼视频| 欧美三级片视频| 黄色视频在线免费看| 二区AV| 伊人网在线免费视频| 日p视频在线观看| 欧产日产国产swag| 抽插影院| 国产毛片777777| 热久久免费| 丁香五月天网站| 九九精品热| 欧美性爱一区| 欧美伊人网在线观看| 444444免费高清在线观看电视剧的注意| 欧美色图网址| 色香蕉在线视频| 五月大香蕉| 精品无码视频在线观看| aaa久久| 天天操b| 性BBwBBwBBwBBw禽| 91av在线播放| 日韩无码久| 天天干天天射天天| 在线无.码| 夜夜福利| 国产色视频一区二区三区QQ号| 国产日韩一区| 久久久久成人片免费观看蜜芽| 亚洲日韩AV无码专区影院| 日韩欧美不卡色不卡| 先锋影音亚洲AV每日资源网站| 久久五月天综合| 国产熟妇码视频app| AV一区二区在线观看| 成人无码区免费| 欧美成人性爱网| 成人黄色在线| 婷婷五月电影| 免费av中文字幕| xxxxxbbbbb| 91蜜桃在线观看| 91人妻网| 无码中文av| 在线免费观看黄片| 少妇人妻一区| 婷婷热| 91麻豆精品国产91久久久久久 | 日韩免费无码视频| 天堂中文字幕在线观看| 动图综合亚洲综合欧美男男| 日韩电影免费在线观看| 国产精品午夜在线| 欧美啪啪网站| 少妇搡BBBB搡BBB搡造水多 | 五月婷在线| 俺来也俺去也| 骚妇一区| 日韩黄色免费网站| 四川美人搡BBw搡BBw| 西西人体大胆裸体A片| 国产无码成人免费| 日韩欧美一级片| 欧美视频在线免费| 一级一级a免一级a做免费线看内裤| 自拍啪啪| 人妻av中文字幕| 亚洲黄色免费网站| 国产无码av| 三级高清无码视频| 免费黄网站在线观看| 狠狠躁日日躁夜夜躁2022麻豆| 日韩va中文字幕无码免费| 国产三级在线播放| 国产精品久久久久久久免牛肉蒲| 日韩无码三级视频| 午夜黄色视频在线观看| 丁香五月天在线视频| 免费看黃色AAAAAA片| 四川妇BBB桑BBB桑BBB| www久草| 国产热| 依人综合网| 中日韩一级片| 性色aV中文字幕| 91丨国产丨白丝| 天堂网亚洲| 欧美一级网站| 色妹子综合| 亚洲欧美激情视频| 在线观看三级网址| 日本少妇BBw| 亚洲.无码.制服.日韩.中文字幕| 亚洲AV成人无码精品直播在线| 日韩欧美中文字幕在线观看| 91麻豆精品A片国产在线观看| 免费一级A| 无码无卡| 无码人妻精品一区二区三| 中文字幕无码在线| 亚洲三级精品| 精品视频999| 国产精品a久久久久| 国产成人视频在线| www.色在线观看| 国产一级a免一级a免费| 操一区| 婷婷啪啪| 五月婷婷色欲| 欧美偷拍一区| 777视频在线观看| 一级免费黄色电影| 国产三级AV在线观看| 91精品青青草| 九九九免费| 午夜精品久久久久久久99黑人 | 久久久久久久久国产| 日韩中文字幕熟妇人妻| 91麻豆一区二区| 高清无码爱爱| 免费精品视频| 亚洲成人精品少妇| 九九re精品视频在线观看| 免费看黄在线看| 亚州AV无码| 日本黄色视频官网| 伊人久久无码| 欧美一区二区三区精品| 欧美日韩国产在线观看| 九九色播| 久久久久性| 日韩在线综合| 天天日天天操天天| 国产日韩二区| 热99视频| 伊人午夜| 国产精品乱码一区二区三区 | 亚洲第一色在线| 影音先锋男人网| av在线资源网| 天天干夜夜爽| 亚洲欧美日韩在线| 奇米88888| 一级免费视频| 四川BBB搡BBB爽爽爽欧美| 亚洲精品秘一区二区三区在线观看 | 牛牛在线精品视频| 亚洲日韩视频在线| 国产精品激情| 欧美日韩中| 国产精品粉嫩福利在线| 国产va| 51午夜福利| 中国老女人性爱视频| 久久麻豆| 久久婷婷无码视频| 高潮免费视频| 日本乱伦视频| 老司机精品视频在线观看| 操B在线视频| 人人妻人人爽人人操| 亚洲国产成人自拍| 日韩精品丰满无码一级A片∴| 国产精品永久| 国产偷拍精品视频| xxxxxbbbbb| 大香蕉伊人影院| 午夜成人爽| 国产日本在线观看| 国产精品久久久久久久久久两年半| 人妻少妇一区二区| 日韩情色| 51妺嘿嘿午夜福利| 欧美性爱高清| 国产精品秘久久久久久| 狠狠撸狠狠干| 久久精品视频播放| 夜夜爽妓女77777毛片A片| 国产高清免费视频| 色小哥| 特级婬片A片AAA毛片AA做头 | 欧美操逼网址| 久久丁香| 日本熟妇在线| 俺来也俺也啪WWW色| 在线成人一区二区| 性BBW| 69人妻人人澡人人爽人人精品| yy午夜福利| 精品无码人妻一区二区媚黑| a视频在线免费观看| 最新毛片网站〖网:.〗| 欧美aaa视频| 天天操天天操天天操| 国产视频精品一区二区三区| 亚洲中文字幕一| 麻豆天美传媒AV果冻传媒| 免费在线观看AV网站| 91成人精品视频| 91视频熟女| 人妻无码一区二区| 精品视频一区二区三区四区| 老汉av| 免费一级黄色| 香蕉国产在线视频|