
Source: juejin.cn/post/
- Feature Characteristics
- Quick Usage
- HTTP Request Annotations
- Configuration Item Description
- Advanced Features
- Global Interceptors
- Call Adapters and Data Converters
- Summary
Using <span>SpringBoot</span> to directly initiate <span>HTTP</span> requests with <span>okhttp</span>, <span>httpClient</span>, or <span>RestTemplate</span> is cumbersome and inconvenient for unified management. Therefore, I recommend a lightweight HTTP client framework suitable for <span>SpringBoot</span> projects: retrofit-spring-boot-starter, which is very simple and convenient to use while providing many functional enhancements. The project has been updated to version <span>2.2.2</span> and will continue to be iteratively optimized.
Introduction
<span>Retrofit</span> is a type-safe HTTP client for <span>Android</span> and <span>Java</span>, with its biggest feature being its support for initiating HTTP requests via interfaces. Meanwhile, <span>spring-boot</span> is the most widely used Java development framework, but the official <span>Retrofit</span> does not support quick integration with the <span>spring-boot</span> framework, which is why we developed <span>retrofit-spring-boot-starter</span>.
<span>retrofit-spring-boot-starter</span> implements quick integration of <span>Retrofit</span> with the <span>spring-boot</span> framework and supports many functional enhancements, greatly simplifying development.
Feature Characteristics
- Custom Injection of OkHttpClient
- Annotation-based Interceptors
- Connection Pool Management
- Log Printing
- Request Retry
- Error Decoders
- Global Interceptors
- Circuit Breaker and Degradation
- HTTP Calls Between Microservices
- Call Adapters
- Data Converters
Quick Usage
Introduce Dependencies
<dependency>
<groupId>com.github.lianjiatech</groupId>
<artifactId>retrofit-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
Define HTTP Interfaces
Interfaces must be marked with the <span>@RetrofitClient</span> annotation! HTTP-related annotations can refer to the official documentation: Retrofit official documentation.
@RetrofitClient(baseUrl = "${test.baseUrl}")
public interface HttpApi {
@GET("person")
Result<Person> getPerson(@Query("id") Long id);
}
Inject and Use
Simply inject the interface into other services to use!
@Service
public class TestService {
@Autowired
private HttpApi httpApi;
public void test() {
// Initiate HTTP requests through httpApi
}
}
HTTP Request Annotations
<span>HTTP</span> request-related annotations all use the <span>retrofit</span> native annotations. For detailed information, refer to the official documentation: Retrofit official documentation, below is a simple explanation.
| Annotation Category | Supported Annotations |
|---|---|
| Request Methods | <span>@GET``@HEAD``@POST``@PUT``@DELETE``@OPTIONS</span> |
| Request Headers | <span>@Header``@HeaderMap``@Headers</span> |
| Query Parameters | <span>@Query``@QueryMap``@QueryName</span> |
| Path Parameters | <span>@Path</span> |
| Form-encoded Parameters | <span>@Field``@FieldMap``@FormUrlEncoded</span> |
| File Upload | <span>@Multipart``@Part``@PartMap</span> |
| URL Parameters | <span>@Url</span> |
Configuration Item Description
<span>retrofit-spring-boot-starter</span> supports multiple configurable properties to address different business scenarios. You can modify them as needed, specific descriptions are as follows:
| Configuration | Default Value | Description |
|---|---|---|
| enable-log | true | Enable log printing |
| logging-interceptor | DefaultLoggingInterceptor | Log printing interceptor |
| pool | Connection pool configuration | |
| disable-void-return-type | false | Disable java.lang.Void return type |
| retry-interceptor | DefaultRetryInterceptor | Request retry interceptor |
| global-converter-factories | JacksonConverterFactory | Global converter factory |
| global-call-adapter-factories | BodyCallAdapterFactory,ResponseCallAdapterFactory | Global call adapter factory |
| enable-degrade | false | Whether to enable circuit breaker degradation |
| degrade-type | sentinel | Circuit breaker degradation implementation method (currently only supports Sentinel) |
| resource-name-parser | DefaultResourceNameParser | Circuit breaker resource name parser, used to parse resource names |
<span>yml</span> configuration method:
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
# Disable void return type
disable-void-return-type: false
# Log printing interceptor
logging-interceptor: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultLoggingInterceptor
# Request retry 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 circuit breaker degradation
enable-degrade: true
# Circuit breaker degradation implementation method
degrade-type: sentinel
# Circuit breaker resource name parser
resource-name-parser: com.github.lianjiatech.retrofit.spring.boot.degrade.DefaultResourceNameParser
Advanced Features
Custom Injection of OkHttpClient
Generally, dynamically creating the <span>OkHttpClient</span> object through the <span>@RetrofitClient</span> annotation properties can meet most usage scenarios. However, in some cases, users may need to customize the <span>OkHttpClient</span>, at which point, you can define a static method returning type <span>OkHttpClient.Builder</span> on the interface to achieve this. 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);
}
The method must be marked with the <span>@OkHttpClientBuilder</span> annotation!
Annotation-based Interceptors
Many times, we want certain HTTP requests under a specific interface to execute unified interception logic. To support this functionality, <span>retrofit-spring-boot-starter</span> provides annotation-based interceptors, achieving URL path-based matching interception. The steps to use are mainly divided into 2 steps:
- Inherit
<span>BasePathMatchInterceptor</span>to write the interceptor handler; - Use
<span>@Intercept</span>to annotate the interface. If you need to configure multiple interceptors, just annotate multiple<span>@Intercept</span>annotations on the interface!
Below is an example of appending a timestamp to the end of a specified request URL to illustrate how to use annotation-based interceptors.
Inherit <span>BasePathMatchInterceptor</span> to write the interceptor handler
@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 <span>@Intercept</span> to annotate the interface
@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);
}
The above <span>@Intercept</span> configuration indicates: intercept requests under the <span>HttpApi</span> interface at the <span>/api/**</span> path (excluding <span>/api/test/savePerson</span>), using the <span>TimeStampInterceptor</span> as the interceptor.
Extend Annotation-based Interceptors
Sometimes, we need to dynamically pass some parameters into the intercept annotation, and then use this parameter during the interception. In such cases, we can extend to implement a custom intercept annotation. The <span>custom intercept annotation</span> must be marked with <span>@InterceptMark</span>, and it must include the include(), exclude(), handler() attribute information. The steps to use are mainly divided into 3 steps:
- Custom intercept annotation
- Inherit
<span>BasePathMatchInterceptor</span>to write the interceptor handler - Use the custom intercept annotation on the interface;
For example, if we need to dynamically add accessKeyId and accessKeySecret signature information in the request header to initiate HTTP requests normally, we can define a signing interceptor annotation <span>@Sign</span> to achieve this.
Custom <span>@Sign</span> Annotation
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@InterceptMark
public @interface Sign {
/**
* Secret key
* Supports placeholder configuration.
*
* @return
*/
String accessKeyId();
/**
* Secret
* Supports placeholder configuration.
*
* @return
*/
String accessKeySecret();
/**
* Interceptor matching path
*
* @return
*/
String[] include() default {"/**"};
/**
* Interceptor exclusion matching, exclude specified path interception
*
* @return
*/
String[] exclude() default {};
/**
* The interceptor class that handles this annotation
* It first tries to get the corresponding Bean from the spring container, if not found, it uses reflection to create one!
*
* @return
*/
Class<? extends BasePathMatchInterceptor> handler() default SignInterceptor.class;
}
There are two points to note about extending the <span>custom intercept annotation</span>:
<span>Custom intercept annotation</span>must be marked with<span>@InterceptMark</span>.- The annotation must include
<span>include(), exclude(), handler()</span>attribute information.
Implement <span>SignInterceptor</span>
@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);
}
}
The above <span>accessKeyId</span> and <span>accessKeySecret</span> field values will be automatically injected based on the <span>@Sign</span> annotation’s <span>accessKeyId()</span> and <span>accessKeySecret()</span> values. If the <span>@Sign</span> specifies a placeholder string, the configuration property value will be used for injection. Additionally, **<span>accessKeyId</span> and <span>accessKeySecret</span> fields must provide <span>setter</span> methods**.
Use on the Interface <span>@Sign</span>
@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);
}
This way, signature information can be automatically added to requests for the specified URL.
Connection Pool Management
By default, all HTTP requests sent through <span>Retrofit</span> will use the default connection pool of <span>max-idle-connections=5 keep-alive-second=300</span>. Of course, we can also configure multiple custom connection pools in the configuration file and specify which one to use through the <span>@RetrofitClient</span>’s <span>poolName</span> property. For example, if we want all requests under a certain interface to use the <span>poolName=test1</span> connection pool, the code implementation is as follows:
- Configure the 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
- Specify the connection pool to use through the
<span>@RetrofitClient</span>’s<span>poolName</span>property.
@RetrofitClient(baseUrl = "${test.baseUrl}", poolName="test1")
public interface HttpApi {
@GET("person")
Result<Person> getPerson(@Query("id") Long id);
}
Log Printing
In many cases, we want to log HTTP request details. The <span>retrofit.enableLog</span> configuration can globally control whether logging is enabled. For each interface, you can control whether logging is enabled through the <span>@RetrofitClient</span>’s <span>enableLog</span> property, and specify the logging level and strategy for each interface through <span>logLevel</span> and <span>logStrategy</span>. <span>retrofit-spring-boot-starter</span> supports 5 logging levels (<span>ERROR</span>, <span>WARN</span>, <span>INFO</span>, <span>DEBUG</span>, <span>TRACE</span>), defaulting to <span>INFO</span>; it supports 4 logging strategies (<span>NONE</span>, <span>BASIC</span>, <span>HEADERS</span>, <span>BODY</span>), defaulting to <span>BASIC</span>. The meanings of the 4 logging strategies are as follows:
<span>NONE</span>: No logs.<span>BASIC</span>: Logs request and response lines.<span>HEADERS</span>: Logs request and response lines and their respective headers.<span>BODY</span>: Logs request and response lines and their respective headers and bodies (if present).
<span>retrofit-spring-boot-starter</span> uses the <span>DefaultLoggingInterceptor</span> to perform the actual logging functionality, which is based on the native <span>HttpLoggingInterceptor</span> of <span>okhttp</span>. Of course, you can also implement your own logging interceptor by inheriting from <span>BaseLoggingInterceptor</span> (for specific implementation, refer to the <span>DefaultLoggingInterceptor</span> implementation), and configure it in the configuration file.
retrofit:
# Log printing interceptor
logging-interceptor: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultLoggingInterceptor
Request Retry
<span>retrofit-spring-boot-starter</span> supports request retry functionality, simply add the <span>@Retry</span> annotation to the interface or method. **<span>@Retry</span> supports retry count <span>maxRetries</span>, retry interval <span>intervalMs</span>, and retry rules <span>retryRules</span> configuration**. The retry rules support three configurations:
<span>RESPONSE_STATUS_NOT_2XX</span>: Retry when the response status code is not<span>2xx</span>;<span>OCCUR_IO_EXCEPTION</span>: Retry when an IO exception occurs;<span>OCCUR_EXCEPTION</span>: Retry when any exception occurs;
By default, it automatically retries when the response status code is not <span>2xx</span> or an IO exception occurs. If needed, you can also inherit from <span>BaseRetryInterceptor</span> to implement your own request retry interceptor and configure it.
retrofit:
# Request retry interceptor
retry-interceptor: com.github.lianjiatech.retrofit.spring.boot.retry.DefaultRetryInterceptor
Error Decoders
When an HTTP request error occurs (including exceptions or response data not meeting expectations), the error decoder can decode the HTTP-related information into a custom exception. You can specify the current interface’s error decoder in the <span>@RetrofitClient</span> annotation’s <span>errorDecoder()</span><span> method; custom error decoders need to implement the </span><code><span>ErrorDecoder</span> interface:
/**
* Error Decoder. ErrorDecoder.
* 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 {
/**
* 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 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 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 Interceptors
Global Application Interceptors
If we need to perform unified interception processing on all HTTP requests in the system, we can customize and implement a global interceptor <span>BaseGlobalInterceptor</span>, and configure it as a <span>bean</span> in the <span>spring</span> container! For example, if we need to ensure that all HTTP requests initiated in the system carry 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 Interceptors
Simply implement the <span>NetworkInterceptor</span> interface and configure it as a <span>bean</span> in the <span>spring</span> container to support automatic weaving of global network interceptors.
Circuit Breaker and Degradation
In a distributed service architecture, performing circuit breaker degradation on unstable external services is one of the important measures to ensure high service availability. Since the stability of external services cannot be guaranteed, when external services are unstable, response times will increase. Consequently, the response time for the caller will also increase, threads will pile up, and eventually, it may exhaust the caller’s thread pool, leading to the entire service becoming unavailable. Therefore, we need to perform circuit breaker degradation on unstable weak dependency service calls to temporarily cut off unstable calls, preventing local instability from causing an overall service avalanche.
<span>retrofit-spring-boot-starter</span> supports circuit breaker degradation functionality, based on Sentinel. Specifically, it supports circuit breaker resource self-discovery and annotation-based degradation rule configuration. To use circuit breaker degradation, simply perform the following operations:
1. Enable Circuit Breaker Degradation Functionality
By default, circuit breaker degradation functionality is disabled, and you need to set the corresponding configuration items to enable it:
retrofit:
# Whether to enable circuit breaker degradation
enable-degrade: true
# Circuit breaker degradation implementation method (currently only supports 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 <span>DefaultResourceNameParser</span>, corresponding to the resource name format <span>HTTP_OUT:GET:http://localhost:8080/api/degrade/test</span>. Users can inherit the <span>BaseResourceNameParser</span> class to implement their own resource name parser.
Additionally, since circuit breaker degradation functionality is optional, enabling it requires users to manually introduce the Sentinel dependency:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.6.3</version>
</dependency>
2. Configure Degradation Rules (Optional)
<span>retrofit-spring-boot-starter</span> supports annotation-based configuration of degradation rules through the <span>@Degrade</span> annotation. The <span>@Degrade</span> annotation can be configured on interfaces or methods, with method-level configurations taking precedence.
@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 supports configuring degradation rules through a configuration center, the annotation-based configuration method can be ignored.
3. Set fallback or fallbackFactory in <span>@RetrofitClient</span> (Optional)
If <span>@RetrofitClient</span> does not set <span>fallback</span> or <span>fallbackFactory</span>, when a circuit breaker is triggered, it will directly throw a <span>RetrofitBlockException</span> exception. Users can customize the return value of the method when a circuit breaker is triggered by setting <span>fallback</span> or <span>fallbackFactory</span>. The <span>fallback</span> class must be an implementation of the current interface, and the <span>fallbackFactory</span> must be an implementation of <span>FallbackFactory<T></span>, with the generic parameter type being the current interface type. Additionally, the <span>fallback</span> and <span>fallbackFactory</span> instances must be configured as <span>Bean</span> in the <span>Spring</span> container.
<span>fallbackFactory</span> differs from <span>fallback</span> mainly in that it can perceive the cause of each circuit breaker (cause). The reference example is 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<HttpDegradeApi> {
/**
* Returns an instance of the fallback appropriate for the given cause
*
* @param cause fallback cause
* @return an instance that implements the retrofit interface.
*/
@Override
public HttpDegradeApi create(Throwable cause) {
log.error("Circuit breaker triggered! ", 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 Calls Between Microservices
To enable microservice calls, the following configurations are required:
Configure <span>ServiceInstanceChooser</span> as a <span>Spring</span> container <span>Bean</span>
Users can implement the <span>ServiceInstanceChooser</span> interface themselves to complete the service instance selection logic and configure it as a <span>Spring</span> container <span>Bean</span>. For <span>Spring Cloud</span> applications, <span>retrofit-spring-boot-starter</span> provides the <span>SpringCloudServiceInstanceChooser</span> implementation, and users only need to configure it as a <span>Spring</span> Bean.
@Bean
@Autowired
public ServiceInstanceChooser serviceInstanceChooser(LoadBalancerClient loadBalancerClient) {
return new SpringCloudServiceInstanceChooser(loadBalancerClient);
}
Use <span>@Retrofit</span>’s <span>serviceId</span> and <span>path</span> properties to achieve HTTP calls between microservices
@RetrofitClient(serviceId = "${jy-helicarrier-api.serviceId}", path = "/m/count", errorDecoder = HelicarrierErrorDecoder.class)
@Retry
public interface ApiCountService {
}
Call Adapters and Data Converters
Call Adapters
<span>Retrofit</span> can adapt the <span>Call<T></span> object to the return value type of the interface method through call adapters <span>CallAdapterFactory</span>. <span>retrofit-spring-boot-starter</span> extends two <span>CallAdapterFactory</span> implementations:
BodyCallAdapterFactory
- Enabled by default, can be disabled by configuring
<span>retrofit.enable-body-call-adapter=false</span>. - Synchronously executes HTTP requests, adapting the response body content to the return value type instance of the interface method.
- Besides
<span>Retrofit.Call<T></span>,<span>Retrofit.Response<T></span>, and<span>java.util.concurrent.CompletableFuture<T></span>, other return types can use this adapter.
ResponseCallAdapterFactory
- Enabled by default, can be disabled by configuring
<span>retrofit.enable-response-call-adapter=false</span>. - Synchronously executes HTTP requests, adapting the response body content to return
<span>Retrofit.Response<T></span>. - If the method’s return value type is
<span>Retrofit.Response<T></span>, this adapter can be used.
Retrofit automatically selects the corresponding <span>CallAdapterFactory</span> for adaptation based on the method return value type! In addition to the default <span>CallAdapterFactory</span>, it supports various forms of method return value types:
<span>Call<T></span>: No adaptation processing, directly returns the<span>Call<T></span>object<span>CompletableFuture<T></span>: Adapts the response body content to return a<span>CompletableFuture<T></span>object<span>Void</span>: Can use<span>Void</span>if the return type is not a concern. If the HTTP status code is not 2xx, it throws an error directly!<span>Response<T></span>: Adapts the response content to return a<span>Response<T></span>object- Any other Java type: Adapts the response body content to return a corresponding Java type object, if the HTTP status code is not 2xx, it throws an error directly!
/**
* Call<T>
* No adaptation processing, directly returns Call<T> object
* @param id
* @return
*/
@GET("person")
Call<Result<Person>> getPersonCall(@Query("id") Long id);
/**
* CompletableFuture<T>
* Adapts the response body content to return a CompletableFuture<T> object
* @param id
* @return
*/
@GET("person")
CompletableFuture<Result<Person>> getPersonCompletableFuture(@Query("id") Long id);
/**
* Void
* Can use Void if the return type is not a concern. If the HTTP status code is not 2xx, it throws an error directly!
* @param id
* @return
*/
@GET("person")
Void getPersonVoid(@Query("id") Long id);
/**
* Response<T>
* Adapts the response content to return a Response<T> object
* @param id
* @return
*/
@GET("person")
Response<Result<Person>> getPersonResponse(@Query("id") Long id);
/**
* Any other Java type
* Adapts the response body content to return a corresponding Java type object, if the HTTP status code is not 2xx, it throws an error directly!
* @param id
* @return
*/
@GET("person")
Result<Person> getPerson(@Query("id") Long id);
We can also extend our own <span>CallAdapter.Factory</span> by inheriting from it!
<span>retrofit-spring-boot-starter</span> supports configuring global call adapter factories through <span>retrofit.global-call-adapter-factories</span>, the factory instance is prioritized to be obtained from the Spring container, and if not obtained, it is created via reflection. The default global call adapter factories are <span>[BodyCallAdapterFactory, ResponseCallAdapterFactory]</span>!
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
For each Java interface, you can also specify the <span>CallAdapter.Factory</span> used by the current interface through the <span>@RetrofitClient</span> annotation’s <span>callAdapterFactories()</span>, the specified factory instance is still prioritized to be obtained from the Spring container.
Note: If the <span>CallAdapter.Factory</span> does not have a public no-argument constructor, please manually configure it as a <span>Spring</span> container <span>Bean</span> object!
Data Converters
<span>Retrofit</span> uses <span>Converter</span> to convert objects annotated with <span>@Body</span> into request bodies and to convert response body data into a <span>Java</span> object. The following types of <span>Converter</span> can be selected:
- 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
<span>retrofit-spring-boot-starter</span> supports configuring global data converter factories through <span>retrofit.global-converter-factories</span>, the converter factory instance is prioritized to be obtained from the Spring container, and if not obtained, it is created via reflection. The default global data converter factory is <span>retrofit2.converter.jackson.JacksonConverterFactory</span>, and you can directly configure the <span>jackson</span> serialization rules through <span>spring.jackson.*</span>, for configuration reference, see Customize the Jackson ObjectMapper!
retrofit:
# Global converter factory
global-converter-factories:
- retrofit2.converter.jackson.JacksonConverterFactory
For each Java interface, you can also specify the <span>Converter.Factory</span> used by the current interface through the <span>@RetrofitClient</span> annotation’s <span>converterFactories()</span>, the specified converter factory instance is still prioritized to be obtained from the Spring container.
Note: If the <span>Converter.Factory</span> does not have a public no-argument constructor, please manually configure it as a <span>Spring</span> container <span>Bean</span> object!
Summary
<span>retrofit-spring-boot-starter</span> is a lightweight <span>HTTP</span> client framework suitable for <span>SpringBoot</span> projects, which has been stably running online for over a year and has been adopted by multiple external companies.