导读:本文从AI时代背景下的软件架构变化谈起,引出其中一个必要的Http客户端技术,进而分析当前Java领域主要的Http客户端和Http框架,并重点阐述了其中优雅度满分的Retrofit框架,以及相关的使用技巧。通过阅读本文,你可以快速了解Java领域的三大Http客户端是什么?三大封装框架是什么?以及熟练掌握Retrofit框架的各种使用技巧。
前沿
在AI技术日新月异的今天,软件架构正经历着前所未有的变革,以适应更加复杂、高效且智能的数据交互需求。作为这一变革中的重要一环,HTTP客户端技术成为了连接前后端、大模型与Java、微服务之间不可或缺的桥梁。在Java这一广泛应用的编程语言中,HTTP客户端的选择与使用不仅关乎到系统的性能与稳定性,还直接影响到开发效率与代码的可维护性。因此对于开发者掌握好Http客户端和框架势必重要!
三大框架是什么?
在Java生态中,三大主流的HTTP客户端分别是:
- Apache HttpClient:作为Apache软件基金会下的一个项目,HttpClient以其丰富的功能、高度的可配置性和广泛的社区支持而闻名。它支持HTTP/1.1和HTTP/2协议,提供了强大的请求执行、响应处理以及连接管理功能。
- OkHttp:由Square公司开发,OkHttp以其高效、易用和强大的错误处理能力而受到青睐。它支持同步和异步请求,内置了连接池、GZIP压缩和HTTP/2等特性,非常适合在Android和Java后端服务中使用。
- HttpUrlConnection:随着Java 11的发布,Java平台内置了一个全新的HTTP客户端API。这个API旨在提供简单、现代的HTTP客户端功能,同时保持与Java平台的紧密集成。它支持HTTP/2和WebSocket,并提供了异步和流式API,使得处理HTTP请求变得更加灵活和高效。
这三大客户端封装实现了HTTP协议,但是在封装的API方法上千差万别,且都不怎么好用,因此开源社区又陆续的出现了三大HTTP框架:
-
Spring RestTemplate(尽管Spring 5引入了WebClient作为更现代的替代品,但RestTemplate在旧项目中仍广泛使用):RestTemplate是Spring框架提供的一个同步客户端,用于简化与HTTP服务的通信。它提供了丰富的模板方法,用于处理HTTP请求,并自动将响应体绑定到Java对象上。
-
Retrofit(注意:虽然Retrofit在Android开发中非常流行,但严格来说它更多被用于Android而非纯Java后端环境。不过,其设计理念和优雅度值得借鉴):Retrofit是一个类型安全的HTTP客户端,用于Android和Java,它基于OkHttp构建,通过注解的方式极大地简化了HTTP请求的编写。Retrofit将HTTP请求抽象为Java接口,开发者只需定义接口方法并添加注解,即可实现复杂的HTTP请求。
-
Feign:Feign是一个声明式的Web服务客户端,它使得编写Web服务客户端变得更加简单。Feign通过创建接口和注解的方式来定义服务绑定,它内部封装了Ribbon和Hystrix,提供了负载均衡和断路器功能,非常适合在微服务架构中使用。
企业开发者往往都使用更为简单的框架,而这3大框架都为主流的,但是他们各自有很明显的区别:
- RestTemplate:Spring把HttpClient、OkHttp、HttpUrlConnection的使用统一成一套API,只做了统一,并API使用上并没有简化太多
- Retrofit:采用声明式方式定义http请求,使得调用http请求变成了对方法进行调用,非常优雅的方式供开发者使用
- Feign:同Retrofit一样,采用声明式的方式定义http请求,但多用于微服务之间通信
在实践开发中,如果开发的是微服务项目则可首选Feign,因为它还支持更多微服务所需要的功能。而如果在单体项目中则首选Retrofit,其优雅的使用方式能大大简化接口的开发、管理**。同时Retrofit底层通过OkHttp进行实现,性能相比其它框架最好。**
Retrofit框架是什么?
Retrofit基于OkHttp开发的、类型安全的Android或Java Http框架。再此我们选用Retrofit框架的重点理由是它基于OkHttp封装,性能好,同时它融入了流行的声明式(PS:只需要定义,不需要实现)开发思想,便于我们开发和学习。
Retrofit入门
在Retrofit中要实现一个Http请求总体来说共有以下2个步骤:
- 1、导入依赖
- 2、声明API
- 3、生效API
导入依赖
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.11.0</version>
</dependency>
声明API
我们可以先创建一个接口类:cn.itcast.star.graph.comfyui.client.api.ComfyuiApi,并按如下代码进行编写:
package cn.itcast.star.graph.comfyui.client.api;
import retrofit2.Call;
import retrofit2.http.GET;
import java.util.HashMap;
public interface ComfyuiApi {
/**
* 获取系统信息
* @return
*/
@GET("/system_stats")
Call<HashMap> getSystemStats();
}
使用Retrofit来声明API,其实就是声明接口方法,比如上述类中定义了一个方法getSystemStats:
- 方法名可以任意取,但建议与http接口名称一致
- 方法通过@GET注解声明当前请求方式是GET并且请求的地址为/system_stats,即获取Comfyui的系统信息接口
- 方法返回结果为Call<HashMap>对象
- Call是固定的返回对象
- HashMap则是接口返回的数据自动转成Map集合存储
生效API
上面声明类要生效,我们还需要配置生效,可创建一个配置类:cn.itcast.star.graph.comfyui.client.config.ComfyuiConfig
package cn.itcast.star.graph.comfyui.client.config;
import cn.itcast.star.graph.comfyui.client.api.ComfyuiApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import retrofit2.Retrofit;
import retrofit2.converter.jackson.JacksonConverterFactory;
import java.io.IOException;
@Configuration
public class ComfyuiConfig {
@Bean
public ComfyuiApi comfyuiApi() throws IOException {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://192.168.100.129:8188")
.addConverterFactory(JacksonConverterFactory.create())
.build();
ComfyuiApi comfyuiApi = retrofit.create(ComfyuiApi.class);
return comfyuiApi;
}
}
在类中:
- 首先通过Retrofit.Builder构建一个Retrofit客户端
- 通过baseUrl指定请求的服务器地址
- 通过addConverterFactory指定请求数据的转换器
- 最后调用 retrofit.create方法创建ComfyuiApi接口的实现
通过上述代码,在Spring IOC中就是声明好了一个可以远程调用获取Comfyui服务器状态的Bean.
测试API
在测试包下创建类:cn.itcast.star.graph.ComfyuiApiTest
package cn.itcast.star.graph;
import cn.itcast.star.graph.comfyui.client.api.ComfyuiApi;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class ComfyuiApiTest {
@Autowired
ComfyuiApi comfyuiApi;
@Test
public void test() throws Exception {
System.out.println(comfyuiApi.getSystemStats().execute().body());
}
}
在类中,直接注入ComfyuiApi,并调用getSystemStats(),即可发起请求并打印出结果:
Retrofit 注解大全
Retrofit为了应对更复杂的Http请求,提供了丰富的注解来支持:
-
@Query:用来声明http查询部分的参数,与@RequestParam类似
-
@Path:用于说明请求路径参数,与@PathVariable类似
@GET("group/{id}/users") Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
-
@Body:用于声明请求体对象,与@RequestBody类似
@POST("users/new") Call<User> createUser(@Body User user);
-
@Multipart:用于说明当前请求以表单形式发起,常常用于带有文件的接口
- 如果是文件字段需要使用 MultipartBody.Part
- 如果是非文件字段需要使用 RequestBody
-
@Part:用于说明一个表单字段
@Multipart @PUT("user/photo") Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
-
@Headers:设定请求头信息
@Headers({ "Accept: application/vnd.github.v3.full+json", "User-Agent: Retrofit-Sample-App" }) @GET("users/{username}") Call<User> getUser(@Path("username") String username);
-
@Header:设定一个头字段
@GET("user") Call<User> getUser(@Header("Authorization") String authorization)
-
@HeaderMap :把一个Map内容设定到请求头中
@GET("user") Call<User> getUser(@HeaderMap Map<String, String> headers)
Retrofit 高级配置
日志开启
Retrofit还提供了打印日志的功能,方便我们进行BUG的排错。Retrofit日志功能默认是关闭的,可以通过以下代码进行开启:
@Bean
public ComfyuiApi comfyuiApi() throws IOException {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.retryOnConnectionFailure(true)
.connectTimeout(30, TimeUnit.SECONDS)
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://192.168.100.129:8188")
.client(okHttpClient)
.addConverterFactory(JacksonConverterFactory.create())
.build();
ComfyuiApi comfyuiApi = retrofit.create(ComfyuiApi.class);
return comfyuiApi;
}
我们之前提供过Retrofit框架底层是通过OkHttp实现,Retrofit的日志功能也是交由底层OkHttp实现:
- 由于要重新设置OkHttp,因此代码中自行构建了OkHttpClient
- 给OkHttpClient增加了日志拦截器HttpLoggingInterceptor,并设置拦截器的日志级别为BODY
- NONE:不输出
- BASIC:输出基本摘要
- HEADERS:输出头信息
- BODY:输出body数据
- 最后第14行通过client方法,重新设定Retrofit底层使用的OkHttp客户端
按上述代码进行修改后,重新运行ComfyuiApiTest类,即可在控制台看见相关的日志输出:
修改数据转换器
Retrofit支持把Http的数据直接转换成各种对象、各种数据格式,要使用那种格式,可通过配置数据转换器自行选择,目前Retrofit支持8种:
- Gson:
com.squareup.retrofit2:converter-gson
- Jackson:
com.squareup.retrofit2:converter-jackson
- Moshi:
com.squareup.retrofit2:converter-moshi
- Protobuf:
com.squareup.retrofit2:converter-protobuf
- Wire:
com.squareup.retrofit2:converter-wire
- Simple XML:
com.squareup.retrofit2:converter-simplexml
- JAXB:
com.squareup.retrofit2:converter-jaxb
- Scalars (primitives, boxed, and String):
com.squareup.retrofit2:converter-scalars
在项目中如果要使用GSON,则先需要导入对应的依赖:
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-gson</artifactId>
<version>2.11.0</version>
</dependency>
然后在代码中通过addConverterFactory方法进行,设定转换工厂类:
工厂类命令为XXXConverterFactory,如果是Jackson则为JacksonConverterFactory,以此类推。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
关注我学Java+AI前沿技术
🔥【Java+AI燃爆新项目】“星图”剧透来袭!🌟
解锁Stable Diffusion、ComfyUI、Ollama等前沿科技,融合Retrofit2与双端异步通信,还有集群队列调度的智慧加成!🚀
想掌握AI应用的核心竞争力吗?快来围观我们的课程项目,一起打造未来科技的璀璨之星!✨ 👀别错过,关注我们,开启你的AI学习新篇章!📚