Simplify Spring Boot HTTP Calls with retrofit-spring-boot-starter: Features, Usage, and Advanced Configuration

This article introduces retrofit-spring-boot-starter, a lightweight HTTP client framework for Spring Boot that integrates Retrofit, detailing its core features, quick start guide, custom interceptors, connection pool management, logging, retry mechanisms, error decoding, global interceptors, circuit breaking, microservice calls, call adapters, data converters, and best practices for production use.

Architect's Tech Stack
Architect's Tech Stack
Architect's Tech Stack
Simplify Spring Boot HTTP Calls with retrofit-spring-boot-starter: Features, Usage, and Advanced Configuration

Hello, I am Peng Lei.

2025 Java Architect: Video Course

In a SpringBoot project, using okhttp, httpClient, or RestTemplate to send HTTP requests is cumbersome and hard to manage uniformly. This article recommends the lightweight HTTP client framework retrofit-spring-boot-starter for SpringBoot projects, which is simple to use and provides many enhancements. The current version is 3.1.5 and will continue to be iterated.

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

Preface

Retrofit

is a type‑safe HTTP client for Android and Java that supports interface‑based requests. However, Retrofit is not officially supported for quick integration with SpringBoot, so retrofit-spring-boot-starter was developed to bridge the two.

retrofit-spring-boot-starter integrates Retrofit with SpringBoot and adds many functional enhancements, greatly simplifying development.

🚀 The project is continuously optimized. Please star the repository and submit issues or PRs!

Features

Custom OkHttpClient injection

Annotation‑based interceptors

Connection pool management

Log printing

Request retry

Error decoder

Global interceptors

Circuit breaking

HTTP calls between microservices

Call adapters

Data converters

Quick Start

Add Dependency

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

Define HTTP Interface

The interface must be annotated with @RetrofitClient .

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

Inject and Use

@Service
public class TestService {
    @Autowired
    private HttpApi httpApi;
    public void test() {
        // invoke HTTP request via httpApi
    }
}

HTTP Request Annotations

Supported annotations include @GET, @POST, @PUT, @DELETE, @HEAD, @OPTIONS, @Header, @HeaderMap, @Headers, @Query, @QueryMap, @QueryName, @Path, @Field, @FieldMap, @FormUrlEncoded, @Multipart, @Part, @PartMap, @Url.

Configuration Items

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
  disable-void-return-type: false
  logging-interceptor: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultLoggingInterceptor
  retry-interceptor: com.github.lianjiatech.retrofit.spring.boot.retry.DefaultRetryInterceptor
  global-converter-factories:
    - retrofit2.converter.jackson.JacksonConverterFactory
  global-call-adapter-factories:
    - com.github.lianjiatech.retrofit.spring.boot.core.BodyCallAdapterFactory
    - com.github.lianjiatech.retrofit.spring.boot.core.ResponseCallAdapterFactory
  enable-degrade: true
  degrade-type: sentinel
  resource-name-parser: com.github.lianjiatech.retrofit.spring.boot.degrade.DefaultResourceNameParser

Custom OkHttpClient Injection

You can define a static method returning OkHttpClient.Builder in the interface to customize the client.

@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("person")
    Result<Person> getPerson(@Query("id") Long id);
}

Annotation‑Based Interceptor

Implement BasePathMatchInterceptor and annotate the interface with @Intercept to apply URL‑based interception.

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

Custom Intercept Annotation

Create a new annotation marked with @InterceptMark that includes include(), exclude(), and handler() attributes, then implement the corresponding interceptor.

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

Connection Pool Management

Define multiple connection pools in the configuration and select a pool for a specific interface via the poolName attribute.

retrofit:
  pool:
    test1:
      max-idle-connections: 3
      keep-alive-second: 100
    test2:
      max-idle-connections: 5
      keep-alive-second: 50
@RetrofitClient(baseUrl = "${test.baseUrl}", poolName="test1")
public interface HttpApi {
    @GET("person")
    Result<Person> getPerson(@Query("id") Long id);
}

Log Printing

Global log control via retrofit.enableLog. Per‑interface control with enableLog, logLevel, and logStrategy. Supported levels: ERROR, WARN, INFO, DEBUG, TRACE (default INFO). Strategies: NONE, BASIC, HEADERS, BODY (default BASIC).

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

Request Retry

Annotate methods or interfaces with @Retry and configure maxRetries, intervalMs, and retryRules (RESPONSE_STATUS_NOT_2XX, OCCUR_IO_EXCEPTION, OCCUR_EXCEPTION).

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

Error Decoder

Implement ErrorDecoder to convert HTTP errors or exceptions into custom runtime exceptions. Specify the decoder with errorDecoder() in @RetrofitClient.

public interface ErrorDecoder {
    default RuntimeException invalidRespDecode(Request request, Response response) {
        if (!response.isSuccessful()) {
            throw RetrofitException.errorStatus(request, response);
        }
        return null;
    }
    default RuntimeException ioExceptionDecode(Request request, IOException cause) {
        return RetrofitException.errorExecuting(request, cause);
    }
    default RuntimeException exceptionDecode(Request request, Exception cause) {
        return RetrofitException.errorUnknown(request, cause);
    }
}

Global Interceptor

Application‑Level Interceptor

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

Network Interceptor

Implement NetworkInterceptor and register it as a Spring bean to be woven into the OkHttp network chain.

Circuit Breaking

Enable circuit breaking with Sentinel by setting enable-degrade: true and degrade-type: sentinel. Define resource name parser if needed. Use @Degrade on interfaces or methods to configure rules, and optionally provide fallback or fallbackFactory for graceful degradation.

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Documented
public @interface Degrade {
    double count();
    int timeWindow() default 5;
    DegradeStrategy degradeStrategy() default DegradeStrategy.AVERAGE_RT;
}
@RetrofitClient(baseUrl = "${jy-helicarrier-api.serviceId}", path = "/m/count", errorDecoder = HelicarrierErrorDecoder.class)
@Retry
public interface ApiCountService { }

Microservice HTTP Calls

Configure a ServiceInstanceChooser bean (e.g., SpringCloudServiceInstanceChooser) to resolve service instances. Use @RetrofitClient(serviceId = "...", path = "/m/count") for inter‑service calls.

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

Call Adapters

Two built‑in adapters: BodyCallAdapterFactory: synchronously executes the request and adapts the response body to the method return type (default enabled). ResponseCallAdapterFactory: synchronously executes the request and returns a Response<T> (default enabled).

Supported return types include Call<T>, CompletableFuture<T>, Void, Response<T>, and any other Java type (non‑2xx responses throw exceptions). Custom adapters can be added via retrofit.global-call-adapter-factories or the callAdapterFactories() attribute on @RetrofitClient.

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

Data Converters

Retrofit uses Converter.Factory to serialize request bodies and deserialize responses. Supported factories include Gson, Jackson, Moshi, Protobuf, Wire, Simple XML, JAXB, etc. The starter defaults to JacksonConverterFactory and can be configured globally via retrofit.global-converter-factories or per‑interface via converterFactories().

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

Conclusion

retrofit-spring-boot-starter

is a lightweight HTTP client framework for SpringBoot projects that has been running stably in production for over a year and is adopted by multiple external companies. Feel free to try it, submit issues, or join the community for rapid support.

JavaMicroservicesSpring BootRetrofithttp-client
Architect's Tech Stack
Written by

Architect's Tech Stack

Java backend, microservices, distributed systems, containerized programming, and more.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.