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.
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.DefaultLoggingInterceptorHTTP Exception Formatter
Customize exception messages by implementing BaseHttpExceptionMessageFormatter and configuring it:
retrofit:
http-exception-message-formatter: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultHttpExceptionMessageFormatterCallAdapter
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
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
