Backend Development 14 min read

Integrating Retrofit with Spring Boot Using retrofit‑spring‑boot‑starter

This article introduces the retrofit‑spring‑boot‑starter library, shows how to add the Maven dependency, configure @RetrofitScan, define HTTP interfaces, inject them into services, and demonstrates advanced features such as annotation‑based interceptors, custom interceptors, connection‑pool management, logging, exception formatting, call adapters, converters, and global interceptors for Spring Boot projects.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Integrating Retrofit with Spring Boot Using retrofit‑spring‑boot‑starter

OkHttp is an open‑source Java HTTP client from Square, and Retrofit is a higher‑level wrapper built on top of OkHttp. The retrofit‑spring‑boot‑starter provides quick integration of Retrofit with Spring Boot, simplifying HTTP API calls.

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 use standard Retrofit annotations:

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

Injecting and Using the Interface

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

    public void test() {
        // invoke HTTP request via httpApi
    }
}

Annotation‑Based Interceptor

Implement a custom interceptor by extending BasePathMatchInterceptor and annotate the target interface method with @Intercept :

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

Custom Annotation @Sign

Create a custom annotation marked with @InterceptMark to add signing headers dynamically:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@InterceptMark
public @interface Sign {
    String accessKeyId();
    String accessKeySecret();
    String[] include() default {"/**"};
    String[] exclude() default {};
    Class
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
getPerson(@Query("id") Long id);
    @POST("savePerson")
    Result
savePerson(@Body Person person);
}

Connection‑Pool Management

Default pool: max-idle-connections=5 keep-alive-second=300 . Custom pools can be defined in application.yml and selected 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 { ... }

Logging

Five log levels (ERROR, WARN, INFO, DEBUG, TRACE) and four strategies (NONE, BASIC, HEADERS, BODY). The default interceptor is DefaultLoggingInterceptor , which delegates to OkHttp's HttpLoggingInterceptor . Custom log interceptors can be provided by extending BaseLoggingInterceptor :

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

HTTP Exception Message Formatter

Customize exception messages by implementing BaseHttpExceptionMessageFormatter and configuring it:

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

CallAdapter Factories

Retrofit can adapt Call<T> to various return types via CallAdapter factories. The starter provides BodyCallAdapterFactory (default) and ResponseCallAdapterFactory . Examples:

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

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

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

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

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

Converters

Retrofit uses Converter factories to serialize request bodies and deserialize responses. Supported converters include Gson, Jackson (default), Moshi, Protobuf, Wire, Simple XML, etc. Custom converters can be added by providing a bean of type Converter.Factory .

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

Conclusion

The retrofit‑spring‑boot‑starter offers an elegant way to use Retrofit in Spring Boot applications, covering dependency setup, interface definition, injection, annotation‑based interceptors, connection‑pool configuration, logging, exception formatting, call adapters, converters, and global interceptors. For more details, refer to the official documentation and GitHub repository.

backendJavaSpring BootInterceptorRetrofitHTTP Client
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login 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.