Give up okhttp and httpclient and choose this awesome immortal tool! Thief Shuang

sycy_ program 2021-02-23 09:06:58
okhttp httpclient choose awesome immortal


give up okhttp、httpClient, I chose this awesome tool ! Thief Shuang

stay SpringBoot Direct use of the project okhttp、httpClient perhaps RestTemplate launch HTTP request , It is not convenient to manage the whole thing . therefore , Here, recommend one for SpringBoot The lightweight of the project HTTP Client Framework retrofit-spring-boot-starter, It is very simple and convenient to use , At the same time, it also provides many functions to enhance . The project has been updated to 2.2.2 edition , And iterative optimization will continue .

Preface
Retrofit Is applicable to Android and Java And the type is safe HTTP client , Its biggest feature is that it supports launching through interfaces HTTP request . and spring-boot Is the most widely used Java Development framework , however Retrofit The official did not support and spring-boot Rapid integration of frameworks , So we developed retrofit-spring-boot-starter.

retrofit-spring-boot-starter Realized Retrofit And spring-boot Rapid integration of frameworks , And it supports many enhancements , Greatly simplifies development .

The project continues to optimize iterations .

features
Custom injection OkHttpClient
Annotating interceptors
Connection pool management
Log printing
Request to retry
Error decoder
Global blocker
Fusing the drop
Between microservices HTTP call
Call adapter
Data converter
Quick to use
Introduce dependencies

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

Definition http Interface
Interface must be used @RetrofitClient Comment mark !http Please refer to the official documents for relevant notes :retrofit Official documents .

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

@GET("person")
Result<Person> getPerson(@Query("id") Long id);

}
Injection use
Inject interfaces into other Service Can be used in !

@Service
public class TestService {

@Autowired
private HttpApi httpApi;
public void test() {
// adopt httpApi launch http request
}

}
HTTP Ask for comments
HTTP Ask for comments , It's all used retrofit Primary annotation . For details, please refer to the official documents :retrofit Official documents , Here's a simple explanation .

Annotation classification Supporting comments
You have selected the content request method for adding links @GET @HEAD @POST @PUT @DELETE @OPTIONS
Request header @Header @HeaderMap @Headers
Query Parameters @Query @QueryMap @QueryName
path Parameters @Path
form-encoded Parameters @Field @FieldMap @FormUrlEncoded
Upload files @Multipart @Part @PartMap
url Parameters @Url
Configuration item description
retrofit-spring-boot-starter Supports multiple configurable properties , To deal with different business scenarios . You can modify it as appropriate , The details are as follows :

To configure The default value is explain
enable-log true Enable log printing
logging-interceptor DefaultLoggingInterceptor Log printing interceptor
pool
Connection pool configuration
disable-void-return-type false Ban java.lang.Void Return type
retry-interceptor DefaultRetryInterceptor Request retrying interceptor
global-converter-factories JacksonConverterFactory Global Converter Factory
global-call-adapter-factories BodyCallAdapterFactory,ResponseCallAdapterFactory Global call adapter factory
enable-degrade false Whether to enable fuse degradation
degrade-type sentinel How to realize fuse degradation ( Currently only supported Sentinel)
resource-name-parser DefaultResourceNameParser Fuse resource name resolver , Used to resolve resource names

yml Configuration mode :

retrofit:
enable-response-call-adapter: true

Enable log printing

enable-log: true

Connection pool configuration

pool:
test1:
max-idle-connections: 3
keep-alive-second: 100
test2:
max-idle-connections: 5
keep-alive-second: 50

Ban void return type

disable-void-return-type: false

Log printing interceptor

logging-interceptor: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultLoggingInterceptor

Request retrying interceptor

retry-interceptor: com.github.lianjiatech.retrofit.spring.boot.retry.DefaultRetryInterceptor

Global Converter Factory

global-converter-factories:
- retrofit2.converter.jackson.JacksonConverterFactory

Global call adapter factory

global-call-adapter-factories:
- com.github.lianjiatech.retrofit.spring.boot.core.BodyCallAdapterFactory
- com.github.lianjiatech.retrofit.spring.boot.core.ResponseCallAdapterFactory

Whether to enable fuse degradation

enable-degrade: true

How to realize fuse degradation

degrade-type: sentinel

Fuse resource name resolver

resource-name-parser: com.github.lianjiatech.retrofit.spring.boot.degrade.DefaultResourceNameParser
Advanced features
Advanced features
Custom injection OkHttpClient
Usually , adopt @RetrofitClient Annotation attributes are created dynamically OkHttpClient Object can satisfy most usage scenarios . But in some cases , Users may need to customize OkHttpClient, This is the time , The return type can be defined on the interface as OkHttpClient.Builder To implement the static method of . The code example is as follows :

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

}
Method must use @OkHttpClientBuilder Comment mark !

Annotating interceptors
A lot of times , We want some of the http Request to execute unified interception processing logic . To support this feature ,retrofit-spring-boot-starter Provides an annotated interceptor , It's based on url Path matching interception . The steps used are mainly divided into 2 Step :

Inherit BasePathMatchInterceptor Write interceptor processor ;
Use... On the interface @Intercept Annotate . To configure multiple interceptors , Mark multiple... On the interface @Intercept Annotations can be !
The following is for the specified request url Back panel timestamp For example, timestamp , Introduce how to use annotation interceptor .

Inherit BasePathMatchInterceptor Write interceptor processor
@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);
}

}
Use... On the interface @Intercept Annotate
@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);

}
above @Intercept Configuration representation : Intercept HttpApi Under the interface /api/** Under the path ( exclude /api/test/savePerson) Request , The interceptor processor uses TimeStampInterceptor.

Extended annotation interceptor
sometimes , We need to dynamically pass in some parameters in intercepting annotations , Then you need to use this parameter when executing interception . This time , We can extend the implementation of custom intercepting annotations . Custom intercept annotations must use @InterceptMark Mark , And the annotation must include include()、exclude()、handler() Attribute information . The steps used are mainly divided into 3 Step :

Custom intercept annotations
Inherit BasePathMatchInterceptor Write interceptor processor
Interface using custom intercept annotations ;
For example, we need to dynamically add accessKeyId、accessKeySecret Signature information can be initiated normally http request , At this time, you can customize a signature interceptor annotation @Sign To achieve . Let's customize @Sign An example of intercepting annotations is given .

Customize @Sign annotation
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@InterceptMark
public @interface Sign {
/**
* secret key key
* Support the configuration of placeholder form .
*
* @return
*/
String accessKeyId();

/**
* secret key
* Support the configuration of placeholder form .
*
* @return
*/
String accessKeySecret();
/**
* Interceptors match paths
*
* @return
*/
String[] include() default {"/**"};
/**
* Interceptors exclude matches , Exclude specific path blocking
*
* @return
*/
String[] exclude() default {};
/**
* The interceptor class that handles the annotation
* Priority from spring The container gets the corresponding Bean, If not , Use reflection to create a !
*
* @return
*/
Class<? extends BasePathMatchInterceptor> handler() default SignInterceptor.class;

}
The extended custom intercept annotations are as follows 2 Point needs attention :

Custom intercept annotations must use @InterceptMark Mark .
The annotation must include include()、exclude()、handler() Attribute information .
Realization 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);
}

}
Above accessKeyId and accessKeySecret Field values are based on @Sign Annotated accessKeyId() and accessKeySecret() Value auto Injection , If @Sign Specifies a string in the form of a placeholder , Then the configuration property value will be taken for injection . in addition ,accessKeyId and accessKeySecret Field must provide setter Method .

Use... On the interface @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);

}
So you can specify url On the request of , Automatically added signature information .

Connection pool management
By default , All through Retrofit Sent http Requests will use max-idle-connections=5 keep-alive-second=300 The default connection pool for . Of course , We can also configure multiple custom connection pools in the configuration file , And then through @RetrofitClient Of poolName Property to specify the use of . For example, we want to make all requests under an interface use poolName=test1 The connection pool , The code implementation is as follows :

Configure connection pool .
retrofit:
\# Connection pool configuration
pool:
test1:
max-idle-connections: 3
keep-alive-second: 100
test2:
max-idle-connections: 5
keep-alive-second: 50
adopt @RetrofitClient Of poolName Property to specify the connection pool to use .
@RetrofitClient(baseUrl = "${test.baseUrl}", poolName="test1")
public interface HttpApi {

 @GET("person")
Result<Person> getPerson(@Query("id") Long id);

}
Log printing
In many cases , We hope that http Request logging . adopt retrofit.enableLog Configuration can globally control whether the log is enabled . For each interface , Can pass @RetrofitClient Of enableLog Control is on , adopt logLevel and logStrategy, You can specify the log printing level and the log printing strategy for each interface .retrofit-spring-boot-starter Support 5 Types of log printing levels (ERROR, WARN, INFO, DEBUG, TRACE), Default INFO; Support 4 A log printing strategy (NONE, BASIC, HEADERS, BODY), Default BASIC.4 The meaning of these log printing strategies is as follows :

NONE:No logs.
BASIC:Logs request and response lines.
HEADERS:Logs request and response lines and their respective headers.
BODY:Logs request and response lines and their respective headers and bodies (if present).
retrofit-spring-boot-starter Default used DefaultLoggingInterceptor Perform the real log printing function , The bottom layer is okhttp Native HttpLoggingInterceptor. Of course , You can also customize your own log printing interceptor , Just inherit BaseLoggingInterceptor( For details, please refer to DefaultLoggingInterceptor The implementation of the ), Then, configure it in the configuration file .

retrofit:

Log printing interceptor

logging-interceptor: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultLoggingInterceptor
Request to retry
retrofit-spring-boot-starter Support request retrial function , Just add... To the interface or method @Retry Annotations can be .@Retry Support the number of retries maxRetries、 Retry interval intervalMs And the retrial rules retryRules To configure . The retry rule supports three configurations :

RESPONSE_STATUS_NOT_2XX: The response status code is not 2xx To execute the retrying ;
OCCUR_IO_EXCEPTION: happen IO Execute retry when exception occurs ;
OCCUR_EXCEPTION: Try again when any exception occurs ;
The default response status code is not 2xx Or it happens IO Automatically retrying in case of exception . If necessary , You can also inherit BaseRetryInterceptor Implement your own request retry interceptor , And then configure it .

retrofit:

Request retrying interceptor

retry-interceptor: com.github.lianjiatech.retrofit.spring.boot.retry.DefaultRetryInterceptor
Error decoder
stay HTTP A request error has occurred ( Or the data does not match the expected response ) When , The error decoder can put HTTP Relevant information is decoded into custom exception . You can @RetrofitClient Annotated errorDecoder() Specifies the error decoder for the current interface , Custom error decoder needs to be implemented ErrorDecoder Interface :

/**

  • Error decoder .ErrorDecoder.
  • When an exception occurs in a request or an invalid response result is received , take HTTP The relevant information is decoded into the exception , It's up to the business to decide if the response is invalid
  • 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 Chen Tianming
    */
    public interface ErrorDecoder {

    /**

    • When there is an invalid response , take HTTP The information is decoded into the exception , Invalid response is judged by the business itself .
    • 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;
      }

    /**

    • When a request occurs IO When abnormal , take HTTP The information is decoded into the exception .
    • 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);
      }

    /**

    • When a request occurs, divide IO When there are other anomalies other than exception , take HTTP The information is decoded into the exception .
    • 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);
      }

}
Global blocker
Global application interceptor
If we need the http Request to perform a unified interception process , You can customize the implementation of global interceptors BaseGlobalInterceptor, And configured to spring In container bean! For example, we need to initiate http request , All with source information .

@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);
}
}
Global network interceptor
Just implement NetworkInterceptor Interface And configured to spring In container bean It supports automatic weaving into global network interceptors .

Fusing the drop
In distributed service architecture , It is one of the important measures to ensure the high availability of services to fuse and degrade the unstable external services . The stability of external services cannot be guaranteed , When external services are unstable , The response time will be longer . Accordingly , The response time of the caller will also increase , Threads will pile up , Eventually, the caller's thread pool may be exhausted , Make the whole service unavailable . Therefore, we need to fuse and demote unstable weak dependent service calls , Temporarily cut off unstable calls , Avoid local instability leading to overall service avalanche .

retrofit-spring-boot-starter Support fuse degradation function , Bottom based Sentinel Realization . say concretely , It supports self discovery of fusing resources and configuration of annotated degradation rules . To use fuse degradation , Just do the following :

  1. Turn on the fuse degradation function
    By default , The fuse degradation function is off , It is necessary to set the corresponding configuration item to turn on the fuse degradation function :

retrofit:

Whether to enable fuse degradation

enable-degrade: true

How to realize fuse degradation ( Currently only supported Sentinel)

degrade-type: sentinel

Resource name parser

resource-name-parser: com.github.lianjiatech.retrofit.spring.boot.degrade.DefaultResourceNameParser
The resource name parser is used to implement user-defined resource names , The default configuration is DefaultResourceNameParser, The corresponding resource name format is HTTP_OUT:GET:http://localhost:8080/api/degrade/test. Users can inherit BaseResourceNameParser Class implements its own resource name parser .

in addition , Since the fuse degradation function is optional , Therefore, it is necessary for the user to introduce fuse degradation Sentinel rely on :

com.alibaba.csp sentinel-core 1.6.3

\2. Configure degradation rules ( Optional ) retrofit-spring-boot-starter Support annotated configuration degradation rules , adopt @Degrade Comments to configure the degradation rules .@Degrade Annotations can be configured on interfaces or methods , Configuration has a higher priority on methods .

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

}
If the application project already supports the configuration of degradation rules through the configuration center , Ignore annotation configuration .

  1. @RetrofitClient Set up fallback perhaps fallbackFactory ( Optional )
    If @RetrofitClient Not set up fallback perhaps fallbackFactory, When the trigger blows , Will be thrown directly RetrofitBlockException abnormal . Users can use the Settings fallback perhaps fallbackFactory To customize the method return value when fusing .fallback Class must be the implementation class of the current interface ,fallbackFactory Must be FallbackFactory Implementation class , The generic parameter type is the current interface type . in addition ,fallback and fallbackFactory The instance must be configured to Spring Container of Bean.

fallbackFactory be relative to fallback, The main difference lies in the ability to sense the abnormal cause of each fusing (cause). Reference examples are as follows :

@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 {

/**
* Returns an instance of the fallback appropriate for the given cause
*
* @param cause fallback cause
* @return Realized retrofit An instance of an interface .an instance that implements the retrofit interface.
*/
@Override
public HttpDegradeApi create(Throwable cause) {
log.error(" The trigger is blown ! ", 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;
}
}

}
Between microservices HTTP call
In order to be able to use microservice calls , The following configuration is required :

To configure ServiceInstanceChooser by Spring Containers Bean
Users can implement it by themselves ServiceInstanceChooser Interface , Complete the selection logic of service instance , And configure it to Spring Container of Bean. about Spring Cloud application ,retrofit-spring-boot-starter Provides SpringCloudServiceInstanceChooser Realization , Users only need to configure it to Spring Of Bean that will do .

@Bean
@Autowired
public ServiceInstanceChooser serviceInstanceChooser(LoadBalancerClient loadBalancerClient) {
return new SpringCloudServiceInstanceChooser(loadBalancerClient);
}
Use @Retrofit Of serviceId and path attribute , Can realize the micro service between HTTP call
@RetrofitClient(serviceId = "${jy-helicarrier-api.serviceId}", path = "/m/count", errorDecoder = HelicarrierErrorDecoder.class)
@Retry
public interface ApiCountService {

}
Call adapter and data transcoder
Call adapter
Retrofit You can call the adapter CallAdapterFactory take Call Object adapts to the return value type of the interface method .retrofit-spring-boot-starter Expand 2 Kind of CallAdapterFactory Realization :

BodyCallAdapterFactory
Enabled by default , configurable retrofit.enable-body-call-adapter=false close
Synchronous execution http request , Adapt the response body to an instance of the return value type of an interface method .
except Retrofit.Call、Retrofit.Response、java.util.concurrent.CompletableFuture outside , Other return types can use this adapter .
ResponseCallAdapterFactory
Enabled by default , configurable retrofit.enable-response-call-adapter=false close
Synchronous execution http request , Adapt the response body to Retrofit.Response return .
If the return value type of the method is Retrofit.Response, You can use the adapter .
Retrofit Automatically select the corresponding... According to the return value type of the method CallAdapterFactory Perform adaptation processing ! add Retrofit default CallAdapterFactory, It can support various forms of method return value types :

Call: No adaptation processing is performed , Go straight back to Call object
CompletableFuture: Adapt the response body to CompletableFuture Object returns
Void: Don't care about return types. You can use Void. If http The status code is not 2xx, Direct throw !
Response: Adapt the response content to Response Object returns
Anything else Java type : Adapt the response body capacity to a corresponding Java Type object returns , If http The status code is not 2xx, Direct throw !
/**
* Call
* No adaptation processing is performed , Go straight back to Call object
* @param id
* @return
*/
@GET("person")
Call<Result> getPersonCall(@Query("id") Long id);

/**
* CompletableFuture<T>
* Adapt the response body to CompletableFuture<T> Object returns
* @param id
* @return
*/
@GET("person")
CompletableFuture<Result<Person>> getPersonCompletableFuture(@Query("id") Long id);
/**
* Void
* Don't care about return types. You can use Void. If http The status code is not 2xx, Direct throw !
* @param id
* @return
*/
@GET("person")
Void getPersonVoid(@Query("id") Long id);
/**
* Response<T>
* Adapt the response content to Response<T> Object returns
* @param id
* @return
*/
@GET("person")
Response<Result<Person>> getPersonResponse(@Query("id") Long id);
/**
* Anything else Java type
* Adapt the response body capacity to a corresponding Java Type object returns , If http The status code is not 2xx, Direct throw !
* @param id
* @return
*/
@GET("person")
Result<Person> getPerson(@Query("id") Long id);

We can also through inheritance CallAdapter.Factory Extension to implement their own CallAdapter!

retrofit-spring-boot-starter Supported by retrofit.global-call-adapter-factories Configure global call adapter factory , Factory examples are preferred from Spring Container acquisition , If not , Then reflection creates . The default global call adapter factory is [BodyCallAdapterFactory, ResponseCallAdapterFactory]!

retrofit:

Global call adapter factory

global-call-adapter-factories:
- com.github.lianjiatech.retrofit.spring.boot.core.BodyCallAdapterFactory
- com.github.lianjiatech.retrofit.spring.boot.core.ResponseCallAdapterFactory
Copy code
For each Java Interface , You can also use @RetrofitClient Annotated callAdapterFactories() Specifies the current interface to use CallAdapter.Factory, The specified factory instance still takes precedence from Spring Container acquisition .

Be careful : If CallAdapter.Factory No, public The parameterless constructor of , Please manually configure it to Spring Container of Bean object !

Data transcoder
Retrofit Use Converter take @Body Annotated objects are converted to request bodies , Convert the response volume data into a Java object , You can choose from the following 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 Supported by retrofit.global-converter-factories Configure the global data converter factory , Converter Factory instances are preferred from Spring Container acquisition , If not , Then reflection creates . The default global data converter factory is retrofit2.converter.jackson.JacksonConverterFactory, You can go straight through spring.jackson.* To configure jackson Serialization rules , Configuration reference Customize the Jackson ObjectMapper!

retrofit:

Global Converter Factory

global-converter-factories:
- retrofit2.converter.jackson.JacksonConverterFactory
For each Java Interface , You can also use @RetrofitClient Annotated converterFactories() Specifies the current interface to use Converter.Factory, The specified converter factory instance still takes precedence from Spring Container acquisition .

Be careful : If Converter.Factory No, public The parameterless constructor of , Please manually configure it to Spring Container of Bean object !

summary
retrofit-spring-boot-starter One applies to SpringBoot The lightweight of the project HTTP Client Framework , It has been running stably on line for more than a year , And a number of external companies have access to it .

版权声明
本文为[sycy_ program]所创,转载请带上原文链接,感谢
https://qdmana.com/2021/02/20210223085940690f.html

  1. How to build a high performance front end intelligent reasoning engine
  2. How to become a professional front end engineer in 2021?
  3. How to transform single / micro service application into serverless application
  4. How to transform single / micro service application into serverless application
  5. How to transform single / micro service application into serverless application
  6. How to connect the ground gas to the micro front end?
  7. How to connect the ground gas to the micro front end?
  8. How to connect the ground gas to the micro front end?
  9. Vue server rendering principle analysis and introduction
  10. Realize the correct loading of text message
  11. Building my own project scaffolding with yeoman
  12. JavaScript advanced prototype and prototype chain
  13. React background management front end system (based on open source framework development) start
  14. JS practical skills breakpoint debugging
  15. I'd like to share with you 20 super easy-to-use Chrome extension plug-ins
  16. Get page element location
  17. Use the powerful API of modern browser to record any interface in the browser and realize export, save and management
  18. Delayed code execution in flutter
  19. Reconfiguration experience of KOA middleware system
  20. Add comments to your blog
  21. Svg editor -- new path
  22. Detailed explanation of debounce and throttle of JavaScript function
  23. Anti shake and throttling and corresponding react hooks package
  24. C2m: the first CSDN article moved to MOOC script 5000 words, detailed painstaking development process, there are renderings and source code at the end of the article
  25. Front end, school recruitment, Taobao, guide
  26. [vue2 & G6] get started quickly
  27. Canvas from the beginning to the pig
  28. Take five minutes to standardize the code comments?
  29. Some thoughts on sass
  30. what?! You haven't filled in the award information yet
  31. How to get the interface + tsdoc needed by TS through swagger
  32. Binary tree
  33. Canvas drawing method in Web screenshot
  34. Front end docker image volume optimization (node + nginx / node + multi-stage construction)
  35. Become a big influence of technology? Coding pages quickly build personal blog
  36. Object and array deconstruction, spread operator, rest operator
  37. Analysis of Axios source code
  38. Two ways to delete useless code in project (Practical)
  39. Edit your picture with canvas
  40. Today's chat: 2-4 years to walk out of the resignation dilemma and comfort zone
  41. JS mechanism 3: stack, heap, garbage collection
  42. [grid compression evaluation] meshquan, meshopt, Draco
  43. Deep understanding of Vue modifier sync [Vue sync modifier example]
  44. WebView for front end engineers
  45. React form source code reading notes
  46. Deep thinking about modern package manager -- why do I recommend pnpm instead of NPM / yarn?
  47. On the sequence of event capture and event bubbling
  48. Help you build a systematic understanding of the front end scaffolding
  49. commander.js Principle analysis
  50. Common usage of nginx
  51. H5 jump to wechat app
  52. Front end algorithm interview must brush questions series [14]
  53. Thinking of cross end practice
  54. Vue server rendering principle analysis and introduction
  55. [KT] vscode plug in development example series (2)
  56. Design ideas of react and Vue framework
  57. JavaScript String.prototype.replaceAll 兼容性导致的问题
  58. JavaScript String.prototype.replaceAll Problems caused by compatibility
  59. 爱奇艺体育:体验Serverless极致扩缩容,资源利用率提升40%
  60. Iqiyi Sports: experience the ultimate expansion and contraction of serverless, and increase the utilization rate of resources by 40%