哎你们有没有那种时候,就是晚上十一二点...人都快困死了还在公司抠代码,然后被人拉群里一顿吐槽,说“你咋还在用HttpClient?Retrofit都火成啥了...”我真是被这句话刺激到了。行吧,今天就跟你们唠唠,这Retrofit到底是个啥,为什么你应该考虑从HttpClient换掉,而且有时候你直接集成进Spring Boot还一堆坑,最后咋优雅用起来。
Retrofit 简介
我先说个场景哈,前几天我在公司楼下抽烟的时候,我们组那个小李还问我:“Retrofit到底比HttpClient好在哪?不是都能发请求么?”你别说,Retrofit真不是单纯的请求工具,它本质其实是个声明式HTTP客户端。你写个Java接口,加点注解,方法签名一弄就能发请求,参数、路径、头都能一行代码解决。而且底层是OkHttp,性能也稳。以前用HttpClient,那配置、拦截器啥的得自己抠半天,是不是?Retrofit就不用,你把请求方法写成接口,后面全给你自动搞定。
Retrofit 和 Spring Boot 集成的那些事
你们有没有用Spring Cloud OpenFeign?Retrofit其实有点像OpenFeign的感觉,但比Feign用起来还精细。可是Retrofit集成Spring Boot早期真心不顺溜,注入啥的得自己写一堆Bean,配置管理也杂乱。后来有个retrofit-spring-boot-starter,一下就不一样了,配置、注入、拦截器都能直接走Spring,真省事。
retrofit-spring-boot-starter 这个玩意儿
我之前真觉得starter都是“玄学”,但这个retrofit-spring-boot-starter确实帮了大忙。你直接配好依赖,HTTP接口用注解声明,参数啥的Spring都能管理,还能全局配置OkHttp、日志、拦截器,包括熔断、降级都有现成方案。你想自定义重试、加日志、玩连接池,starter里都一条龙服务,反正就是不用再手撸一堆模板代码。
功能特性
你别以为它只是发请求,retrofit-spring-boot-starter的细节其实挺多的。
自定义OkHttpClient你比如说安全要求高,超时时间、代理啥的要自己配?直接注入自己的OkHttpClient,甚至能用注解@OkHttpClientBuilder定制。
注解式拦截器以前加拦截器不都得写一堆配置,现在直接写个类继承BasePathMatchInterceptor,加个@Intercept注解,路径随便拦,想怎么拦怎么拦。
连接池管理有的接口量大,有的量小,你不想都用一个池子?starter可以多连接池,你用@RetrofitClient(poolName="xxx")指定池子就完事了。
日志打印日志级别啥的支持ERROR、WARN、INFO、DEBUG、TRACE,策略也有BASIC、HEADERS、BODY。你要自定义,继承BaseLoggingInterceptor写就行。
请求重试加个@Retry注解,能配重试次数、间隔、甚至重试规则,复杂点的还支持自定义重试拦截器。
错误解码器想捕捉异常啥的?实现ErrorDecoder接口就能把错误响应、IO异常全解成你想要的Java对象,方便调试。
全局拦截器实现BaseGlobalInterceptor或NetworkInterceptor,所有请求全都能拦,统一处理header、token、签名啥的。
熔断降级(Sentinel支持)你直接开启配置,加@Degrade注解,配置好fallback或fallbackFactory,接口挂了能优雅降级。
微服务间HTTP调用你有ServiceInstanceChooser,serviceId加path就能搞服务间通信,跟Feign那套差不多。
调用适配器和数据转换器默认支持Call、CompletableFuture、Response等多种返回类型,也能自定义CallAdapter.Factory,转码支持Jackson、Gson等,接口级别都能配。
快速上手Retrofit-Spring-Boot
行,别光说不练,咋用?我拿自己前两天加班踩的坑跟你们说。
1. 引入依赖
<groupId>com.github.lianjiatech</groupId>
<artifactId>retrofit-spring-boot-starter</artifactId>
<version>2.8.2</version>
版本号自己看下最新的,不然有的功能用不了。
2. 定义HTTP接口就像这样:
@RetrofitClient(baseUrl = "https://api.example.com")
public interface UserApi {
@GET("/users/{id}")
User getUserById(@Path("id") Long id);
@POST("/users")
User createUser(@Body User user);
}
是不是挺清爽?
3. 注入使用你Spring项目里直接@Autowired就行:
@Autowired
private UserApi userApi;
public void test() {
User u = userApi.getUserById(123L);
}
省得你每次都new一堆东西了。
HTTP 请求相关注解说明
你们肯定用惯了SpringMVC的注解,这Retrofit注解风格也很像:
@GET, @POST, @PUT, @DELETE这些不多说。
@Header, @Headers, @HeaderMap可以动态或静态加header。
@Query, @QueryMap, @QueryName加URL参数超方便。
@Path直接路径变量,跟Spring类似。
@Field, @FormUrlEncoded搞表单提交。
@Multipart, @Part上传文件必备,图片啥的就靠它了。
@Url支持动态URL,你别看这小众场景,其实偶尔用还真有用。
配置项简单聊两句
配置都放application.yml里。基础配置比如日志开关、连接池、降级开关、转码器,starter文档写得挺全,你只要照着配基本踩不了坑。比如日志级别:
retrofit:
log-level: info
log-strategy: body
连接池、超时也都能分接口定制,不怕量大接口拖慢小接口。
高级玩法
我知道你们有的要魔改,Retrofit光用基础的肯定不爽,starter支持各种自定义:
自定义OkHttpClient注入你写个静态方法,加@OkHttpClientBuilder,直接定制拦截器、连接池啥的:
@OkHttpClientBuilder
public static OkHttpClient.Builder okHttpClientBuilder() {
return new OkHttpClient.Builder()
.connectTimeout(5, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS);
}
注解式拦截器想根据路径拦截接口,自己写个继承BasePathMatchInterceptor的类,加@Intercept注解就行,比如只拦截/users/*请求。
自定义注解式拦截器比如你想接口都加签名校验,可以自定义注解@Sign,写个SignInterceptor,参数都能自动注入。
多连接池配置你有高并发接口,直接指定池名@RetrofitClient(poolName = "bigPool"),starter帮你管。
自定义日志拦截器继承BaseLoggingInterceptor实现你自己的日志规则,打印花里胡哨的内容都能搞。
重试机制加@Retry,或者自己写重试拦截器,支持次数、间隔、规则自定义。
错误解码器自己实现ErrorDecoder,响应内容异常啥的全能转成自己的异常对象。
全局拦截器实现BaseGlobalInterceptor,所有请求拦一遍,比如加全局header、token啥的,配置里直接绑。
熔断降级只要你Sentinel配好,@Degrade注解能直接绑接口,写个fallback或fallbackFactory降级逻辑也就那几行。
服务间调用配置ServiceInstanceChooser,serviceId+path就能做微服务间调用,跟OpenFeign用法神似。
调用适配器和数据转码器
返回类型你爱怎么来怎么来,普通Java对象、CompletableFuture、Response、Call,都支持。自己有特殊需求,直接扩展CallAdapter.Factory。
转码器默认是Jackson,接口特殊需求自己加Gson、Fastjson都行。配置全局、按接口定制都支持。
反正吧,我是觉得Retrofit-spring-boot-starter用起来就是舒服,不用天天为HttpClient的各种配置头大,尤其是接口一多,拦截器、日志、熔断、降级、连接池都成体系了。偶尔也得感谢下starter的作者,真给我们这些写CRUD的人省了不少事。