Simplify Spring Boot HTTP Calls with Retrofit Spring Boot Starter

This guide explains how to integrate Retrofit into a Spring Boot project using the retrofit‑spring‑boot‑starter, covering dependency setup, annotation configuration, custom interceptors, connection pool management, logging, exception formatting, call adapters, converters, and global interception to make HTTP client development more elegant and maintainable.

Programmer DD
Programmer DD
Programmer DD
Simplify Spring Boot HTTP Calls with Retrofit Spring Boot Starter

OkHttp is an open‑source Java HTTP client from Square, and Square also provides Retrofit, a higher‑level wrapper that lets you define HTTP requests with annotated interfaces.

If your project still uses RestTemplate or raw OkHttp, you can switch to Retrofit for a cleaner approach.

The retrofit-spring-boot-starter quickly integrates Retrofit with Spring Boot and adds several enhancements, greatly simplifying HTTP interface calls in a Spring Boot application.

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

Adding the Dependency

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

Configuring @RetrofitScan

Apply @RetrofitScan to a @Configuration class or directly on the Spring Boot main class:

@SpringBootApplication
@RetrofitScan("com.github.lianjiatech.retrofit.spring.boot.test")
public class RetrofitTestApplication {
    public static void main(String[] args) {
        SpringApplication.run(RetrofitTestApplication.class, args);
    }
}

Defining an HTTP Interface

Mark the interface with @RetrofitClient and declare request methods:

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

Injecting and Using the Interface

@Service
public class TestService {
    @Autowired
    private HttpApi httpApi;

    public void test() {
        // call httpApi methods here
    }
}

With these steps, sending HTTP requests via an interface becomes straightforward.

Annotation‑Based Interceptor

You can apply a custom interceptor to specific requests by extending BasePathMatchInterceptor and using @Intercept on the interface:

@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 Annotation @Sign

Create a custom annotation to add signing headers automatically:

@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

Default pool: max-idle-connections=5 keep-alive-second=300. You can define custom pools in application.yml and select them with poolName:

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 { ... }

Logging

Configure log level and strategy via logLevel and logStrategy. Supported levels: ERROR, WARN, INFO, DEBUG, TRACE. Strategies: NONE, BASIC, HEADERS, BODY. The starter uses DefaultLoggingInterceptor (based on OkHttp’s HttpLoggingInterceptor).

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

HTTP Exception Formatter

Customize exception messages by implementing BaseHttpExceptionMessageFormatter and configuring it:

retrofit:
  http-exception-message-formatter: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultHttpExceptionMessageFormatter

CallAdapter

Retrofit can adapt Call<T> to various return types via CallAdapterFactory. The starter provides two factories:

BodyCallAdapterFactory : enabled by default, adapts responses to the method’s return type (except for raw Call, Response, CompletableFuture).

ResponseCallAdapterFactory : enabled by default, adapts to Response<T> when the method returns that type.

Examples:

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

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

@GET("person")
Void getPersonVoid(@Query("id") Long id);

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

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

Converter

Retrofit uses a Converter to serialize request bodies and deserialize responses. Supported converters include Gson, Jackson, Moshi, Protobuf, Wire, Simple XML. The starter defaults to Jackson. To use another, add the corresponding dependency and register its Converter.Factory as a Spring bean.

Global Interceptor (BaseGlobalInterceptor)

Implement a global interceptor to apply logic to every HTTP request, e.g., adding a source header:

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

With these configurations, you have a complete, elegant HTTP client solution for Spring Boot projects.

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

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Spring BootInterceptorRetrofitHTTP clientStarter
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

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.