# retrofit-spring-boot-starter
**Repository Path**: vpen/retrofit-spring-boot-starter
## Basic Information
- **Project Name**: retrofit-spring-boot-starter
- **Description**: A spring-boot starter for retrofit, supports rapid integration and feature enhancements.(适用于retrofit的spring-boot启动器,支持快速集成和功能增强)
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 125
- **Created**: 2025-07-29
- **Last Updated**: 2025-07-29
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## retrofit-spring-boot-starter
[](https://www.apache.org/licenses/LICENSE-2.0.html)
[](https://travis-ci.com/github/LianjiaTech/retrofit-spring-boot-starter)
[](https://maven-badges.herokuapp.com/maven-central/com.github.lianjiatech/retrofit-spring-boot-starter)
[](https://github.com/LianjiaTech/retrofit-spring-boot-starter/releases)
[](https://docs.oracle.com/javase/8/docs/index.html)
[](https://docs.spring.io/spring-boot/docs/2.1.5.RELEASE/reference/htmlsingle/)
[](https://juejin.im/user/3562073404738584/posts)
[ ](https://img.ljcdn.com/hc-picture/6302d742-ebc8-4649-95cf-62ccf57a1add)
[中文文档](https://github.com/LianjiaTech/retrofit-spring-boot-starter/blob/master/README.md)
**A spring-boot starter for retrofit, supports rapid integration and feature enhancements.**
1. *Spring Boot 3.x project,please use retrofit-spring-boot-starter 3.x*。
2. *Spring Boot 1.x/2.x project,please use retrofit-spring-boot-starter 2.x*。
> Open source is not easy, please give me a star⭐️
## Features
- [x] [Customize OkHttpClient](#Customize-OkHttpClient)
- [x] [Annotation Interceptor](#Annotation-Interceptor)
- [x] [Log Print](#Log-Print)
- [x] [Request Retry](#Request-Retry)
- [x] [Fusing Degrade](#Fusing-Degrade)
- [x] [Error Decoder](#Error-Decoder)
- [x] [HTTP Calls Between Microservices](#HTTP-Calls-Between-Microservices)
- [x] [Global Interceptor](#Global-Interceptor)
- [x] [Call Adapter](#Call-Adapter)
- [x] [Data Converter](#Data-Converter)
- [x] [Meta-annotation](#Meta-annotation)
- [x] [Other Examples](#Other-Examples)
## Quick Start
### Import Dependencies
```xml
com.github.lianjiatechretrofit-spring-boot-starter3.1.3
```
### Define HTTP Interface
**Interfaces must be marked with the `@RetrofitClient` annotation**!For HTTP related annotations, please refer to the official documentation:[Retrofit official documentation](https://square.github.io/retrofit/).
```java
@RetrofitClient(baseUrl = "${test.baseUrl}")
public interface UserService {
/**
* 根据id查询用户姓名
*/
@POST("getName")
String getName(@Query("id") Long id);
}
```
> Notice:**The method request path should be cautiously used at the beginning of `/`**. For `Retrofit`, if `baseUrl=http://localhost:8080/api/test/` and the method request path is `person`, then the complete request path of the method is: `http://localhost: 8080/api/test/person`. If the method request path is `/person`, the complete request path of the method is: `http://localhost:8080/person`.
### Inject Using
**Inject the interface into other services to use**:
```java
@Service
public class BusinessService {
@Autowired
private UserService userService;
public void doBusiness() {
// call userService
}
}
```
**Automatically use `Spring Boot` scan path for `RetrofitClient` registration by default**. You can also manually specify the scan path by adding `@RetrofitScan` to the configuration class.
## HTTP Related Annotations
`HTTP` request related annotations, all use `Retrofit` native annotations, the following is a brief description:
| Classification | Supported Annotations |
|------------|-----------|
| Request Method |`@GET` `@HEAD` `@POST` `@PUT` `@DELETE` `@OPTIONS` `@HTTP`|
| Request Header |`@Header` `@HeaderMap` `@Headers`|
| Query Parameter |`@Query` `@QueryMap` `@QueryName`|
| Path Parameter |`@Path`|
| Form-encoded Parameter |`@Field` `@FieldMap` `@FormUrlEncoded`|
| Request Body |`@Body`|
| File Upload |`@Multipart` `@Part` `@PartMap`|
| Url Parameter |`@Url`|
> For details, please refer to the official documentation:[Retrofit official documentation](https://square.github.io/retrofit/)
## Configuration Properties
The component supports multiple configurable properties to deal with different business scenarios. The specific supported configuration properties and default values are as follows:
```yaml
retrofit:
global-converter-factories:
- com.github.lianjiatech.retrofit.spring.boot.core.BasicTypeConverterFactory
- retrofit2.converter.jackson.JacksonConverterFactory
global-call-adapter-factories:
global-log:
enable: true
log-level: info
log-strategy: basic
aggregate: true
global-retry:
enable: false
interval-ms: 100
max-retries: 2
retry-rules:
- response_status_not_2xx
- occur_io_exception
global-timeout:
read-timeout-ms: 10000
write-timeout-ms: 10000
connect-timeout-ms: 10000
call-timeout-ms: 0
degrade:
degrade-type: none
global-sentinel-degrade:
enable: false
# Threshold corresponding to each degrade policy. Average response time (ms), exceptions ratio (0-1), number of exceptions (1-N)
count: 1000
time-window: 5
# Degradation strategy (0: average response time; 1: ratio of exceptions; 2: number of exceptions)
grade: 0
global-resilience4j-degrade:
enable: false
# Get CircuitBreakerConfig from {@link CircuitBreakerConfigRegistry} based on this name as a global circuit breaker configuration
circuit-breaker-config-name: defaultCircuitBreakerConfig
auto-set-prototype-scope-for-path-math-interceptor: true
```
## Advanced Features
### Timeout config
If you only need to modify the timeout time of `OkHttpClient`, you can modify it through the relevant fields of `@RetrofitClient`, or modify the global timeout configuration.
### Customize OkHttpClient
If you need to modify other configuration of `OkHttpClient`, you can do it by customizing `OkHttpClient`, the steps are as follows:
Implement the `SourceOkHttpClientRegistrar` interface and call the `SourceOkHttpClientRegistry#register()` method to register the `OkHttpClient`.
```java
@Component
public class CustomOkHttpClientRegistrar implements SourceOkHttpClientRegistrar {
@Override
public void register(SourceOkHttpClientRegistry registry) {
// 注册customOkHttpClient,超时时间设置为1s
registry.register("customOkHttpClient", new OkHttpClient.Builder()
.connectTimeout(Duration.ofSeconds(1))
.writeTimeout(Duration.ofSeconds(1))
.readTimeout(Duration.ofSeconds(1))
.addInterceptor(chain -> chain.proceed(chain.request()))
.build());
}
}
```
2. Specify the `OkHttpClient` to be used by the current interface through `@RetrofitClient.sourceOkHttpClient`.
```java
@RetrofitClient(baseUrl = "${test.baseUrl}", sourceOkHttpClient = "customOkHttpClient")
public interface CustomOkHttpUserService {
/**
* 根据id查询用户信息
*/
@GET("getUser")
User getUser(@Query("id") Long id);
}
```
> Note: The component will not use the specified `OkHttpClient` directly, but will create a new one based on that `OkHttpClient`.
### Annotation Interceptor
The component provides **Annotation Interceptor**, which supports interception based on url path matching. The steps used are as follows:
1. Inherit `BasePathMatchInterceptor`
2. Use the `@Intercept` annotation to specify the interceptor to use
> If you need to use multiple interceptors, you can mark multiple `@Intercept` annotations on the interface.
The following is an example of "splicing timestamp behind the specified request url" to introduce how to use annotation interceptors.
#### Inherit `BasePathMatchInterceptor`
```java
@Component
public class PathMatchInterceptor extends BasePathMatchInterceptor {
@Override
protected Response doIntercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
// response的Header加上path.match
return response.newBuilder().header("path.match", "true").build();
}
}
```
By default, **component will automatically set `scope` of `BasePathMatchInterceptor` to `prototype`**.
This feature can be turned off by `retrofit.auto-set-prototype-scope-for-path-math-interceptor=false`. After closing, you need to manually set `scope` to `prototype`.
```java
@Component
@Scope("prototype")
public class PathMatchInterceptor extends BasePathMatchInterceptor {
}
```
#### Use the `@Intercept` annotation to specify the interceptor to use
```java
@RetrofitClient(baseUrl = "${test.baseUrl}")
@Intercept(handler = PathMatchInterceptor.class, include = {"/api/user/**"}, exclude = "/api/user/getUser")
// @Intercept() 如果需要使用多个路径匹配拦截器,继续添加@Intercept即可
public interface InterceptorUserService {
/**
* 根据id查询用户姓名
*/
@POST("getName")
Response getName(@Query("id") Long id);
/**
* 根据id查询用户信息
*/
@GET("getUser")
Response getUser(@Query("id") Long id);
}
```
### Custom Interception Annotation
Sometimes, we need to dynamically pass in some parameters in the "Interception Annotation", and then use these parameters when intercepting. At this time, we can use "Custom Interception Annotation", the steps are as follows:
1. Custom annotation. The `@InterceptMark` tag must be used, and the `include, exclude, handler` fields must be included in the annotation.
2. inherit `BasePathMatchInterceptor`
3. Use custom annotation on interfaces
For example, we need to "dynamically add `accessKeyId` and `accessKeySecret` signature information in the request header to initiate an HTTP request", which can be achieved by customizing the `@Sign` annotation.
#### Custom `@Sign` Annotation
```java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@InterceptMark
public @interface Sign {
String accessKeyId();
String accessKeySecret();
String[] include() default {"/**"};
String[] exclude() default {};
Class extends BasePathMatchInterceptor> handler() default SignInterceptor.class;
}
```
The interceptor specified in the `@Sign` annotation is `SignInterceptor`.
#### Implement `SignInterceptor`
```java
@Component
@Setter
public class SignInterceptor extends BasePathMatchInterceptor {
private String accessKeyId;
private String accessKeySecret;
@Override
public Response doIntercept(Chain chain) throws IOException {
Request request = chain.request();
Request newReq = request.newBuilder()
.addHeader("accessKeyId", accessKeyId)
.addHeader("accessKeySecret", accessKeySecret)
.build();
Response response = chain.proceed(newReq);
return response.newBuilder().addHeader("accessKeyId", accessKeyId)
.addHeader("accessKeySecret", accessKeySecret).build();
}
}
```
> Note: The `accessKeyId` and `accessKeySecret` fields must provide a `setter` method.
The `accessKeyId` and `accessKeySecret` field values of the interceptor will be automatically injected according to the `accessKeyId()` and `accessKeySecret()` values of the `@Sign` annotation, if `@Sign` specifies a string in the form of a placeholder , the configuration property value will be taken for injection.
#### Using `@Sign` on the interface
```java
@RetrofitClient(baseUrl = "${test.baseUrl}")
@Sign(accessKeyId = "${test.accessKeyId}", accessKeySecret = "${test.accessKeySecret}", include = "/api/user/getAll")
public interface InterceptorUserService {
/**
* 查询所有用户信息
*/
@GET("getAll")
Response> getAll();
}
```
### Log Print
Component support supports global log printing and declarative log printing.
#### Global Log Printing
By default, global log printing is enabled, and the default configuration is as follows:
```yaml
retrofit:
global-log:
enable: true
log-level: info
log-strategy: basic
aggregate: true
logName: com.github.lianjiatech.retrofit.spring.boot.log.LoggingInterceptor
```
The meanings of the four log printing strategies are as follows:
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).
#### Declarative Log Printing
If only some requests are required to print the log, you can use the `@Logging` annotation on the relevant interface or method.
#### Log printing custom extension
If you need to modify the log printing behavior, you can inherit `LoggingInterceptor` and configure it as a `Spring bean`.
### Request Retry
Component support supports global retry and declarative retry.
#### Global Retry
Global retry is disabled by default, and the default configuration items are as follows:
```yaml
retrofit:
global-retry:
enable: false
interval-ms: 100
max-retries: 2
retry-rules:
- response_status_not_2xx
- occur_io_exception
```
The retry rule supports three configurations:
1. `RESPONSE_STATUS_NOT_2XX`: retry when response status code is not `2xx`
2. `OCCUR_IO_EXCEPTION`: Execute retry when IO exception occurs
3. `OCCUR_EXCEPTION`: perform a retry on any exception
#### Declarative Retry
If only a part of the request needs to be retried, you can use the `@Retry` annotation on the corresponding interface or method.
#### Request retry custom extension
If you need to modify the request retry behavior, you can inherit `RetryInterceptor` and configure it as a `Spring bean`.
### Fusing Degrade
The circuit breaker degrade is disabled by default, and currently supports both `sentinel` and `resilience4j` implementations.
```yaml
retrofit:
degrade:
# Fuse degrade type. The default is none, which means that fuse downgrade is not enabled
degrade-type: sentinel
```
#### Sentinel
Configure `degrade-type=sentinel` to enable, and then declare the `@SentinelDegrade` annotation on the relevant interface or method.
Remember to manually import `Sentinel` dependencies:
```xml
com.alibaba.cspsentinel-core1.6.3
```
In addition, global `Sentinel` circuit breaker degrade are also supported:
```yaml
retrofit:
degrade:
degrade-type: sentinel
global-sentinel-degrade:
enable: true
# Other sentinel global configuration
```
#### Resilience4j
Configure `degrade-type=resilience4j` to enable. Then declare `@Resilience4jDegrade` on the relevant interface or method.
Remember to manually import `Resilience4j` dependencies:
```xml
io.github.resilience4jresilience4j-circuitbreaker1.7.1
```
In addition, global `Resilience4j` circuit breaker degrade are also supported:
```yaml
retrofit:
degrade:
degrade-type: resilience4j
global-resilience4j-degrade:
enable: true
# Get CircuitBreakerConfig from {@link CircuitBreakerConfigRegistry} based on this name as a global circuit breaker configuration
circuit-breaker-config-name: defaultCircuitBreakerConfig
```
Circuit breaker configuration management:
Implement the `CircuitBreakerConfigRegistrar` interface and register the `CircuitBreakerConfig`.
```java
@Component
public class CustomCircuitBreakerConfigRegistrar implements CircuitBreakerConfigRegistrar {
@Override
public void register(CircuitBreakerConfigRegistry registry) {
registry.register(Constants.DEFAULT_CIRCUIT_BREAKER_CONFIG, CircuitBreakerConfig.ofDefaults());
registry.register("testCircuitBreakerConfig", CircuitBreakerConfig.custom()
.slidingWindowType(CircuitBreakerConfig.SlidingWindowType.TIME_BASED)
.failureRateThreshold(20)
.minimumNumberOfCalls(5)
.permittedNumberOfCallsInHalfOpenState(5)
.build());
}
}
```
Specify the `CircuitBreakerConfig` via `circuitBreakerConfigName`. Include `retrofit.degrade.global-resilience4j-degrade.circuit-breaker-config-name` or `@Resilience4jDegrade.circuitBreakerConfigName`
#### Extended circuit breaker degrade
If the user needs to use another circuit breaker degrade implementation, inherit `BaseRetrofitDegrade` and configure it with `Spring Bean`.
#### Configure fallback or fallbackFactory (optional)
If `@RetrofitClient` does not set `fallback` or `fallbackFactory`, when a circuit breaker is triggered, a `RetrofitBlockException` exception will be thrown directly. Users can customize the method return value when blown by setting `fallback` or `fallbackFactory`.
> Note: `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` instances must be configured as `Spring Bean`.
The main difference between `fallbackFactory` and `fallback` is that it can perceive the abnormal cause (cause) of each fuse. The reference example is as follows:
```java
@Slf4j
@Service
public class HttpDegradeFallback implements HttpDegradeApi {
@Override
public Result test() {
Result fallback = new Result<>();
fallback.setCode(100)
.setMsg("fallback")
.setBody(1000000);
return fallback;
}
}
```
```java
@Slf4j
@Service
public class HttpDegradeFallbackFactory implements FallbackFactory {
@Override
public HttpDegradeApi create(Throwable cause) {
log.error("触发熔断了! ", cause.getMessage(), cause);
return new HttpDegradeApi() {
@Override
public Result test() {
Result fallback = new Result<>();
fallback.setCode(100)
.setMsg("fallback")
.setBody(1000000);
return fallback;
}
};
}
}
```
### Error Decoder
When a request error occurs in `HTTP` (including an exception or the response data does not meet expectations), the error decoder can decode the `HTTP` related information into a custom exception. You can use `errorDecoder()` in the `@RetrofitClient` annotation
Specifies the error decoder of the current interface. Custom error decoders need to implement the `ErrorDecoder` interface:
### HTTP Calls Between Microservices
#### Inherit `ServiceInstanceChooser`
Users can implement the `ServiceInstanceChooser` interface by themselves, complete the selection logic of service instances, and configure them as `Spring Bean`. For `Spring Cloud`
Application, it can be implemented using the following.
```java
@Service
public class SpringCloudServiceInstanceChooser implements ServiceInstanceChooser {
private LoadBalancerClient loadBalancerClient;
@Autowired
public SpringCloudServiceInstanceChooser(LoadBalancerClient loadBalancerClient) {
this.loadBalancerClient = loadBalancerClient;
}
/**
* Chooses a ServiceInstance URI from the LoadBalancer for the specified service.
*
* @param serviceId The service ID to look up the LoadBalancer.
* @return Return the uri of ServiceInstance
*/
@Override
public URI choose(String serviceId) {
ServiceInstance serviceInstance = loadBalancerClient.choose(serviceId);
Assert.notNull(serviceInstance, "can not found service instance! serviceId=" + serviceId);
return serviceInstance.getUri();
}
}
```
#### Specify `serviceId` and `path`
```java
@RetrofitClient(serviceId = "user", path = "/api/user")
public interface ChooserOkHttpUserService {
/**
* 根据id查询用户信息
*/
@GET("getUser")
User getUser(@Query("id") Long id);
}
```
## Global Interceptor
### Global Application Interceptor
If we need to perform unified interception processing for `HTTP` requests of the entire system, we can implement the global interceptor `GlobalInterceptor` and configure it as `spring Bean`.
```java
@Component
public class MyGlobalInterceptor implements GlobalInterceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
// response的Header加上global
return response.newBuilder().header("global", "true").build();
}
}
```
### Global Network Interceptor
Implement the `NetworkInterceptor` interface and configure it as a `spring Bean`.
## Call Adapter
`Retrofit` can adapt `Call` objects to the return type of interface methods through `CallAdapterFactory`. The component extends some `CallAdapterFactory` implementations:
1. `BodyCallAdapterFactory`
- Execute the `HTTP` request synchronously, adapting the content of the response body to the return value type of the method.
- Any method return value type can use `BodyCallAdapterFactory`, with the lowest priority.
2. `ResponseCallAdapterFactory`
- Execute the `HTTP` request synchronously, adapt the content of the response body to `Retrofit.Response` and return it.
- The `ResponseCallAdapterFactory` can only be used if the method return value type is `Retrofit.Response`.
3. Reactive programming related `CallAdapterFactory`, supports the following method return value types:
**`Retrofit` will select the corresponding `CallAdapterFactory` to perform adaptation processing according to the return value type of the method**. The currently supported return value types are as follows:
- String:Adapt `Response Body` to `String` to return.
- Basic type (`Long`/`Integer`/`Boolean`/`Float`/`Double`): adapt `Response Body` to the above basic type
- Any `Java` type: adapt the `Response Body` to the corresponding `Java` object and return it
- `CompletableFuture`: adapt `Response Body` to a `CompletableFuture` object and return it
- `Void`: `Void` can be used regardless of the return type
- `Response`: `Response`: adapt `Response` to a `Response` object and return it
- `Call`: No adaptation processing is performed, and the `Call` object is returned directly
- `Mono`: `Project Reactor` reactive return type
- `Single`: `Rxjava` reactive return type (supports `Rxjava2/Rxjava3`)
- `Completable`: `Rxjava` reactive return type, `HTTP` request has no response body (supports `Rxjava2/Rxjava3`)
`CallAdapter` can be extended by extending `CallAdapter.Factory`.
Components support configuring global call adapter factories via `retrofit.global-call-adapter-factories`:
```yaml
retrofit:
# The `CallAdaptorFactory` factory extended by the component has been built in, please do not repeat the configuration here
global-call-adapter-factories:
# ...
```
For each Java interface, you can also specify the `CallAdapter.Factory` used by the current interface through `@RetrofitClient.callAdapterFactories`.
> Recommendation: configure `CallAdapter.Factory` as `Spring Bean`
### Data Converter
`Retrofit` uses `Converter` to convert the object annotated with `@Body` into `Request Body`, and `Response Body` into a `Java` object. You can choose the following `Converter`:
- [Gson](https://github.com/google/gson): com.squareup.Retrofit:converter-gson
- [Jackson](https://github.com/FasterXML/jackson): com.squareup.Retrofit:converter-jackson
- [Moshi](https://github.com/square/moshi/): com.squareup.Retrofit:converter-moshi
- [Protobuf](https://developers.google.com/protocol-buffers/): com.squareup.Retrofit:converter-protobuf
- [Wire](https://github.com/square/wire): com.squareup.Retrofit:converter-wire
- [Simple XML](http://simple.sourceforge.net/): com.squareup.Retrofit:converter-simplexml
- [JAXB](https://docs.oracle.com/javase/tutorial/jaxb/intro/index.html): com.squareup.retrofit2:converter-jaxb
- fastJson:com.alibaba.fastjson.support.retrofit.Retrofit2ConverterFactory
Configure the global `Converter.Factory` through `retrofit.global-converter-factories`, the default is `retrofit2.converter.jackson.JacksonConverterFactory`.
If you need to modify the `Jackson` configuration, you can override the `bean` configuration of the `JacksonConverterFactory` by yourself.
```yaml
retrofit:
global-converter-factories:
- com.github.lianjiatech.retrofit.spring.boot.core.BasicTypeConverterFactory
- retrofit2.converter.jackson.JacksonConverterFactory
```
For each `Java` interface, you can also specify the `Converter.Factory` used by the current interface through `@RetrofitClient.converterFactories`.
> Recommendation: Configure `Converter.Factory` as `Spring Bean`.
### Meta-annotation
Annotations such as `@RetrofitClient`, `@Retry`, `@Logging`, `@Resilience4jDegrade` support meta-annotations, inheritance, and `@AliasFor`.
```java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Inherited
@RetrofitClient(baseUrl = "${test.baseUrl}")
@Logging(logLevel = LogLevel.WARN)
@Retry(intervalMs = 200)
public @interface MyRetrofitClient {
@AliasFor(annotation = RetrofitClient.class, attribute = "converterFactories")
Class extends Converter.Factory>[] converterFactories() default {GsonConverterFactory.class};
@AliasFor(annotation = Logging.class, attribute = "logStrategy")
LogStrategy logStrategy() default LogStrategy.BODY;
}
```
## Other Examples
### Form Parameter
```java
@FormUrlEncoded
@POST("token/verify")
Object tokenVerify(@Field("source") String source,@Field("signature") String signature,@Field("token") String token);
@FormUrlEncoded
@POST("message")
CompletableFuture