兄弟们,鹏磊今天来聊聊声明式 HTTP 客户端 @HttpExchange 这玩意儿;这是 Spring Framework 7.0 引入的新功能,用起来比 RestTemplate 和 WebClient 简单多了。今天咱从最基础的开始,一步步讲到高级用法,让你彻底掌握这玩意儿。这功能确实实用,代码量能减少一大半,值得好好研究。
一、入门篇:什么是声明式 HTTP 客户端?
1. 为什么需要声明式 HTTP 客户端?
传统的 HTTP 客户端(RestTemplate、WebClient)用起来比较繁琐,每次调用都要写一堆代码;声明式 HTTP 客户端只需要定义一个接口,Spring 会自动生成代理实现,代码量能减少 60% 以上。
// 传统方式:使用 RestTemplate,代码繁琐
@Service
public class TraditionalUserService {
@Autowired
private RestTemplate restTemplate;
public User getUser(Long id) {
// 每次调用都要写 URL、处理响应、处理异常,代码重复
String url = "http://api.example.com/users/" + id;
try {
ResponseEntity<User> response = restTemplate.getForEntity(url, User.class);
return response.getBody();
} catch (RestClientException e) {
// 异常处理
throw new RuntimeException("获取用户失败", e);
}
}
public User createUser(User user) {
String url = "http://api.example.com/users";
try {
ResponseEntity<User> response = restTemplate.postForEntity(url, user, User.class);
return response.getBody();
} catch (RestClientException e) {
throw new RuntimeException("创建用户失败", e);
}
}
}
// 声明式方式:使用 @HttpExchange,代码简洁
@HttpExchange(url = "http://api.example.com") // 定义基础 URL
public interface UserClient {
@GetExchange("/users/{id}") // GET 请求
User getUser(@PathVariable Long id); // 方法签名就是接口定义,不用写实现
@PostExchange("/users") // POST 请求
User createUser(@RequestBody User user); // 自动序列化和反序列化
}
@Service
public class DeclarativeUserService {
@Autowired
private UserClient userClient; // 注入客户端,Spring 自动生成代理
public User getUser(Long id) {
// 直接调用,代码简洁多了
return userClient.getUser(id);
}
public User createUser(User user) {
// 直接调用,不用写 HTTP 请求代码
return userClient.createUser(user);
}
}
2. 第一个声明式 HTTP 客户端
让我们从最简单的例子开始:
// 第一步:定义 HTTP 客户端接口
@HttpExchange(url = "http://api.example.com") // 基础 URL,所有方法都基于这个路径
public interface SimpleUserClient {
// GET 请求:获取用户信息
@GetExchange("/users/{id}") // 路径是 /users/{id},{id} 是路径变量
User getUser(@PathVariable Long id); // @PathVariable 绑定路径变量
}
// 第二步:配置 HTTP 客户端
@Configuration
public class HttpClientConfig {
// 创建 RestClient(推荐,Spring Framework 6.1+ 引入)
@Bean
public RestClient restClient() {
return RestClient.builder()
.baseUrl("http://api.example.com") // 设置基础 URL
.build();
}
// 创建 RestClient 适配器
@Bean
public RestClientAdapter restClientAdapter(RestClient restClient) {
// RestClientAdapter 将 RestClient 适配到声明式 HTTP 客户端
return RestClientAdapter.create(restClient);
}
// 创建 HTTP 服务代理工厂
@Bean
public HttpServiceProxyFactory httpServiceProxyFactory(RestClientAdapter adapter) {
// HttpServiceProxyFactory 根据接口定义自动生成代理实现
return HttpServiceProxyFactory.builderFor(adapter).build();
}
// 创建 UserClient 代理 Bean
@Bean
public SimpleUserClient simpleUserClient(HttpServiceProxyFactory factory) {
// 使用工厂创建代理,Spring 会自动实现接口方法
return factory.createClient(SimpleUserClient.class);
}
}
// 第三步:使用客户端
@Service
public class UserService {
@Autowired
private SimpleUserClient userClient; // 注入客户端
public User getUser(Long id) {
// 直接调用,就像调用普通方法一样
return userClient.getUser(id);
}
}
3. 支持的 HTTP 方法
声明式 HTTP 客户端支持所有常见的 HTTP 方法:
@HttpExchange(url = "http://api.example.com")
public interface HttpMethodsClient {
// GET 请求:获取资源
@GetExchange("/users/{id}")
User getUser(@PathVariable Long id);
// POST 请求:创建资源
@PostExchange("/users")
User createUser(@RequestBody User user);
// PUT 请求:更新资源(完整更新)
@PutExchange("/users/{id}")
User updateUser(@PathVariable Long id, @RequestBody User user);
// PATCH 请求:部分更新资源
@PatchExchange("/users/{id}")
User patchUser(@PathVariable Long id, @RequestBody Map<String, Object> updates);
// DELETE 请求:删除资源
@DeleteExchange("/users/{id}")
void deleteUser(@PathVariable Long id);
}
二、进阶篇:参数处理和配置
1. 路径变量(@PathVariable)
路径变量用于在 URL 中传递参数:
@HttpExchange(url = "http://api.example.com")
public interface PathVariableClient {
// 单个路径变量
@GetExchange("/users/{id}")
User getUser(@PathVariable Long id);
// 多个路径变量
@GetExchange("/users/{userId}/posts/{postId}")
Post getUserPost(
@PathVariable("userId") Long userId, // 可以指定变量名
@PathVariable("postId") Long postId
);
// 路径变量和查询参数组合
@GetExchange("/users/{id}/orders")
List<Order> getUserOrders(
@PathVariable Long id,
@RequestParam("status") String status // 查询参数
);
}
2. 查询参数(@RequestParam)
查询参数用于在 URL 后面添加参数:
@HttpExchange(url = "http://api.example.com")
public interface RequestParamClient {
// 单个查询参数
@GetExchange("/users")
List<User> getUsers(@RequestParam("page") int page);
// 多个查询参数
@GetExchange("/users")
List<User> getUsers(
@RequestParam("page") int page,
@RequestParam("size") int size,
@RequestParam("sort") String sort
);
// 可选查询参数
@GetExchange("/users")
List<User> getUsers(
@RequestParam("page") int page,
@RequestParam(value = "size", required = false) Integer size, // 可选参数
@RequestParam(value = "sort", required = false, defaultValue = "id") String sort // 默认值
);
// Map 作为查询参数(会展开为多个参数)
@GetExchange("/search")
List<User> searchUsers(@RequestParam Map<String, String> params);
}
3. 请求头(@RequestHeader)
请求头用于传递额外的信息:
@HttpExchange(url = "http://api.example.com")
public interface RequestHeaderClient {
// 单个请求头
@GetExchange("/users/{id}")
User getUser(
@PathVariable Long id,
@RequestHeader("Authorization") String token // 认证 token
);
// 多个请求头
@GetExchange("/users/{id}")
User getUser(
@PathVariable Long id,
@RequestHeader("Authorization") String token,
@RequestHeader("X-Request-ID") String requestId
);
// Map 作为请求头(会展开为多个请求头)
@GetExchange("/users/{id}")
User getUser(
@PathVariable Long id,
@RequestHeader Map<String, String> headers
);
}
4. 请求体(@RequestBody)
请求体用于传递复杂对象:
@HttpExchange(url = "http://api.example.com")
public interface RequestBodyClient {
// POST 请求,传递对象
@PostExchange("/users")
User createUser(@RequestBody User user); // 自动序列化为 JSON
// PUT 请求,传递对象
@PutExchange("/users/{id}")
User updateUser(@PathVariable Long id, @RequestBody User user);
// PATCH 请求,传递 Map(部分更新)
@PatchExchange("/users/{id}")
User patchUser(@PathVariable Long id, @RequestBody Map<String, Object> updates);
// 传递多个对象(使用 @RequestPart 或自定义)
@PostExchange("/users/{id}/avatar")
void uploadAvatar(
@PathVariable Long id,
@RequestPart("file") MultipartFile file,
@RequestPart("metadata") Map<String, String> metadata
);
}
5. 响应处理
可以返回不同类型的响应:
@HttpExchange(url = "http://api.example.com")
public interface ResponseClient {
// 返回对象(自动反序列化)
@GetExchange("/users/{id}")
User getUser(@PathVariable Long id);
// 返回 ResponseEntity(包含状态码、响应头等)
@GetExchange("/users/{id}")
ResponseEntity<User> getUserWithResponse(@PathVariable Long id);
// 返回 Void(不关心响应体)
@DeleteExchange("/users/{id}")
void deleteUser(@PathVariable Long id);
// 返回 String(原始响应)
@GetExchange("/users/{id}")
String getUserAsString(@PathVariable Long id);
// 返回 List(数组响应)
@GetExchange("/users")
List<User> getUsers();
}
三、进阶篇:高级配置
1. 类型级别的配置
可以在接口级别配置公共属性:
// 类型级别的配置,所有方法都继承这些配置
@HttpExchange(
url = "http://api.example.com", // 基础 URL
accept = "application/json", // 默认 Accept 头
contentType = "application/json" // 默认 Content-Type 头
)
public interface TypeLevelConfigClient {
@GetExchange("/users/{id}")
User getUser(@PathVariable Long id);
// 方法级别的配置会覆盖类型级别的配置
@PostExchange(contentType = "application/xml") // 覆盖类型级别的 contentType
User createUser(@RequestBody User user);
}
2. 方法级别的配置
可以在方法级别配置特定属性:
@HttpExchange(url = "http://api.example.com")
public interface MethodLevelConfigClient {
// 配置请求方法和路径
@GetExchange("/users/{id}")
User getUser(@PathVariable Long id);
// 配置内容类型
@PostExchange(contentType = "application/json")
User createUser(@RequestBody User user);
// 配置接受类型
@GetExchange(value = "/users/{id}", accept = "application/json")
User getUser(@PathVariable Long id);
// 配置多个属性
@PostExchange(
value = "/users",
contentType = "application/json",
accept = "application/json"
)
User createUser(@RequestBody User user);
}
3. 使用 RestClient 配置
RestClient 是 Spring Framework 6.1+ 引入的新客户端,推荐使用:
@Configuration
public class RestClientConfig {
@Bean
public RestClient restClient() {
return RestClient.builder()
.baseUrl("http://api.example.com") // 基础 URL
.defaultHeader("User-Agent", "MyApp/1.0") // 默认请求头
.defaultHeader("Accept", "application/json") // 默认 Accept
.requestInterceptor((request, body, execution) -> {
// 请求拦截器,可以在发送请求前修改请求
System.out.println("发送请求: " + request.getURI());
return execution.execute(request, body);
})
.requestInterceptor((request, body, execution) -> {
// 可以添加多个拦截器
long start = System.currentTimeMillis();
ClientHttpResponse response = execution.execute(request, body);
long duration = System.currentTimeMillis() - start;
System.out.println("请求耗时: " + duration + "ms");
return response;
})
.build();
}
@Bean
public RestClientAdapter restClientAdapter(RestClient restClient) {
return RestClientAdapter.create(restClient);
}
@Bean
public HttpServiceProxyFactory httpServiceProxyFactory(RestClientAdapter adapter) {
return HttpServiceProxyFactory.builderFor(adapter).build();
}
}
4. 使用 WebClient 配置(响应式)
如果你用的是响应式编程,可以用 WebClient:
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient() {
return WebClient.builder()
.baseUrl("http://api.example.com") // 基础 URL
.defaultHeader("User-Agent", "MyApp/1.0") // 默认请求头
.defaultHeader("Accept", "application/json") // 默认 Accept
.filter((request, next) -> {
// 响应式过滤器
return next.exchange(request)
.doOnNext(response -> {
System.out.println("响应状态: " + response.statusCode());
});
})
.build();
}
@Bean
public WebClientAdapter webClientAdapter(WebClient webClient) {
return WebClientAdapter.create(webClient);
}
@Bean
public HttpServiceProxyFactory httpServiceProxyFactory(WebClientAdapter adapter) {
return HttpServiceProxyFactory.builderFor(adapter).build();
}
}
// 响应式客户端接口
@HttpExchange(url = "http://api.example.com")
public interface ReactiveUserClient {
// 返回 Mono(单个结果)
@GetExchange("/users/{id}")
Mono<User> getUser(@PathVariable Long id);
// 返回 Flux(多个结果)
@GetExchange("/users")
Flux<User> getUsers();
// 接收 Mono 参数
@PostExchange("/users")
Mono<User> createUser(@RequestBody Mono<User> userMono);
}
5. 使用 RestTemplate 配置(兼容旧代码)
如果你还在用 RestTemplate,也可以配置:
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
// 配置消息转换器
List<HttpMessageConverter<?>> converters = new ArrayList<>();
converters.add(new MappingJackson2HttpMessageConverter());
restTemplate.setMessageConverters(converters);
// 配置请求拦截器
restTemplate.setInterceptors(Collections.singletonList(
(request, body, execution) -> {
System.out.println("发送请求: " + request.getURI());
return execution.execute(request, body);
}
));
return restTemplate;
}
@Bean
public RestTemplateAdapter restTemplateAdapter(RestTemplate restTemplate) {
return RestTemplateAdapter.create(restTemplate);
}
@Bean
public HttpServiceProxyFactory httpServiceProxyFactory(RestTemplateAdapter adapter) {
return HttpServiceProxyFactory.builderFor(adapter).build();
}
}
四、精通篇:高级用法
1. 错误处理
声明式 HTTP 客户端支持多种错误处理方式:
@HttpExchange(url = "http://api.example.com")
public interface ErrorHandlingClient {
// 方式1:抛出异常(默认行为)
@GetExchange("/users/{id}")
User getUser(@PathVariable Long id); // 如果状态码不是 2xx,会抛出异常
// 方式2:返回 ResponseEntity,手动处理
@GetExchange("/users/{id}")
ResponseEntity<User> getUserWithResponse(@PathVariable Long id);
// 方式3:使用自定义错误处理器
@GetExchange("/users/{id}")
User getUserWithErrorHandler(@PathVariable Long id);
}
// 配置错误处理器
@Configuration
public class ErrorHandlerConfig {
@Bean
public RestClient restClient() {
return RestClient.builder()
.baseUrl("http://api.example.com")
.defaultStatusHandler(
HttpStatusCode::is4xxClientError, // 4xx 错误
(request, response) -> {
// 自定义错误处理
throw new UserNotFoundException("用户不存在");
}
)
.defaultStatusHandler(
HttpStatusCode::is5xxServerError, // 5xx 错误
(request, response) -> {
throw new ServerException("服务器错误");
}
)
.build();
}
}
// 使用示例
@Service
public class UserService {
@Autowired
private ErrorHandlingClient userClient;
public User getUser(Long id) {
try {
return userClient.getUser(id);
} catch (UserNotFoundException e) {
// 处理用户不存在的情况
return null;
} catch (ServerException e) {
// 处理服务器错误
throw new RuntimeException("服务暂时不可用", e);
}
}
}
2. 请求和响应拦截器
可以添加拦截器来记录日志、添加请求头等:
@Configuration
public class InterceptorConfig {
@Bean
public RestClient restClient() {
return RestClient.builder()
.baseUrl("http://api.example.com")
.requestInterceptor((request, body, execution) -> {
// 请求拦截器:在发送请求前执行
HttpHeaders headers = request.getHeaders();
headers.add("X-Request-ID", UUID.randomUUID().toString()); // 添加请求 ID
headers.add("X-Timestamp", String.valueOf(System.currentTimeMillis())); // 添加时间戳
// 记录请求日志
System.out.println("请求方法: " + request.getMethod());
System.out.println("请求 URL: " + request.getURI());
System.out.println("请求头: " + headers);
return execution.execute(request, body);
})
.requestInterceptor((request, body, execution) -> {
// 响应拦截器:在收到响应后执行
long start = System.currentTimeMillis();
ClientHttpResponse response = execution.execute(request, body);
long duration = System.currentTimeMillis() - start;
// 记录响应日志
System.out.println("响应状态: " + response.getStatusCode());
System.out.println("响应耗时: " + duration + "ms");
return response;
})
.build();
}
}
3. 认证处理
可以配置各种认证方式:
@Configuration
public class AuthenticationConfig {
// 方式1:Basic 认证
@Bean
public RestClient basicAuthRestClient() {
return RestClient.builder()
.baseUrl("http://api.example.com")
.requestInterceptor((request, body, execution) -> {
// 添加 Basic 认证头
String auth = "username:password";
String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes());
request.getHeaders().set("Authorization", "Basic " + encodedAuth);
return execution.execute(request, body);
})
.build();
}
// 方式2:Bearer Token 认证
@Bean
public RestClient bearerTokenRestClient(@Value("${api.token}") String token) {
return RestClient.builder()
.baseUrl("http://api.example.com")
.defaultHeader("Authorization", "Bearer " + token) // 默认添加 Bearer Token
.build();
}
// 方式3:OAuth2 认证(需要 Spring Security)
@Bean
public RestClient oauth2RestClient(OAuth2AuthorizedClientService clientService) {
return RestClient.builder()
.baseUrl("http://api.example.com")
.requestInterceptor((request, body, execution) -> {
// 从 OAuth2 服务获取 token
OAuth2AuthorizedClient client = clientService.loadAuthorizedClient(
"my-client", "user-name"
);
if (client != null) {
String token = client.getAccessToken().getTokenValue();
request.getHeaders().set("Authorization", "Bearer " + token);
}
return execution.execute(request, body);
})
.build();
}
}
// 使用认证客户端
@HttpExchange(url = "http://api.example.com")
public interface AuthenticatedClient {
@GetExchange("/users/{id}")
User getUser(@PathVariable Long id); // 会自动添加认证头
}
4. 重试机制
可以配置重试机制来处理临时失败:
@Configuration
public class RetryConfig {
@Bean
public RestClient restClient() {
return RestClient.builder()
.baseUrl("http://api.example.com")
.requestInterceptor((request, body, execution) -> {
// 实现重试逻辑
int maxRetries = 3;
int retryCount = 0;
while (retryCount < maxRetries) {
try {
ClientHttpResponse response = execution.execute(request, body);
// 如果是 5xx 错误,重试
if (response.getStatusCode().is5xxServerError()) {
retryCount++;
if (retryCount < maxRetries) {
Thread.sleep(1000 * retryCount); // 指数退避
continue;
}
}
return response;
} catch (IOException e) {
retryCount++;
if (retryCount < maxRetries) {
try {
Thread.sleep(1000 * retryCount);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new RuntimeException(ie);
}
} else {
throw new RuntimeException("请求失败,已重试 " + maxRetries + " 次", e);
}
}
}
throw new RuntimeException("请求失败");
})
.build();
}
}
5. 超时配置
可以配置连接超时和读取超时:
@Configuration
public class TimeoutConfig {
@Bean
public RestClient restClient() {
// 使用 HttpClient(需要添加依赖)
HttpClient httpClient = HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000) // 连接超时 5 秒
.responseTimeout(Duration.ofSeconds(10)); // 响应超时 10 秒
ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);
return RestClient.builder()
.baseUrl("http://api.example.com")
.clientConnector(connector)
.build();
}
}
6. 分组管理 HTTP 服务
Spring Framework 7.0 支持分组管理 HTTP 服务,方便管理多个服务:
// 定义多个 HTTP 服务接口
@HttpExchange(url = "http://weather-api.example.com")
public interface WeatherService {
@GetExchange("/weather/{city}")
Weather getWeather(@PathVariable String city);
}
@HttpExchange(url = "http://user-api.example.com")
public interface UserService {
@GetExchange("/users/{id}")
User getUser(@PathVariable Long id);
}
// 分组配置
@Configuration
@ImportHttpServices(group = "weather", types = {WeatherService.class}) // 天气服务组
@ImportHttpServices(group = "user", types = {UserService.class}) // 用户服务组
public class HttpServicesGroupConfig extends AbstractHttpServiceRegistrar {
@Bean
public RestClientHttpServiceGroupConfigurer groupConfigurer() {
return groups -> groups
.filterByName("weather", "user") // 过滤出这两个组
.configureClient((group, builder) -> {
// 为每个组配置客户端
if ("weather".equals(group.getName())) {
builder.baseUrl("http://weather-api.example.com")
.defaultHeader("User-Agent", "WeatherApp/1.0");
} else if ("user".equals(group.getName())) {
builder.baseUrl("http://user-api.example.com")
.defaultHeader("User-Agent", "UserApp/1.0");
}
});
}
}
7. 自定义序列化和反序列化
可以自定义 JSON 序列化和反序列化:
@Configuration
public class SerializationConfig {
@Bean
public RestClient restClient(ObjectMapper objectMapper) {
// 配置 ObjectMapper
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
// 创建消息转换器
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(objectMapper);
// 配置 RestClient(需要通过 RestTemplate 或自定义)
// 这里简化示例,实际需要更复杂的配置
return RestClient.builder()
.baseUrl("http://api.example.com")
.build();
}
}
8. 文件上传和下载
可以处理文件上传和下载:
@HttpExchange(url = "http://api.example.com")
public interface FileClient {
// 文件上传
@PostExchange(value = "/upload", contentType = "multipart/form-data")
UploadResponse uploadFile(
@RequestPart("file") MultipartFile file,
@RequestPart("description") String description
);
// 文件下载
@GetExchange("/download/{fileId}")
ResponseEntity<Resource> downloadFile(@PathVariable String fileId);
}
// 使用示例
@Service
public class FileService {
@Autowired
private FileClient fileClient;
public void uploadFile(MultipartFile file) {
UploadResponse response = fileClient.uploadFile(file, "文件描述");
System.out.println("上传成功: " + response.getFileId());
}
public void downloadFile(String fileId, String savePath) throws IOException {
ResponseEntity<Resource> response = fileClient.downloadFile(fileId);
Resource resource = response.getBody();
if (resource != null) {
Files.copy(resource.getInputStream(), Paths.get(savePath), StandardCopyOption.REPLACE_EXISTING);
}
}
}
五、最佳实践
1. 接口设计原则
- 单一职责:每个接口只负责一个服务的调用
- 命名清晰:方法名要能清楚表达功能
- 参数合理:避免参数过多,可以用对象封装
// 好的设计
@HttpExchange(url = "http://api.example.com")
public interface UserClient {
@GetExchange("/users/{id}")
User getUser(@PathVariable Long id);
@PostExchange("/users")
User createUser(@RequestBody CreateUserRequest request); // 使用请求对象
}
// 不好的设计
@HttpExchange(url = "http://api.example.com")
public interface BadClient {
// 参数太多,不易维护
@PostExchange("/users")
User createUser(
@RequestParam String name,
@RequestParam String email,
@RequestParam String phone,
@RequestParam String address,
@RequestParam Integer age
);
}
2. 错误处理策略
- 统一异常处理:定义统一的异常类
- 重试机制:对临时失败进行重试
- 降级处理:服务不可用时返回默认值
// 统一异常类
public class ApiException extends RuntimeException {
private final int statusCode;
public ApiException(int statusCode, String message) {
super(message);
this.statusCode = statusCode;
}
public int getStatusCode() {
return statusCode;
}
}
// 错误处理配置
@Configuration
public class ErrorHandlingConfig {
@Bean
public RestClient restClient() {
return RestClient.builder()
.baseUrl("http://api.example.com")
.defaultStatusHandler(
HttpStatusCode::isError,
(request, response) -> {
throw new ApiException(
response.getStatusCode().value(),
"API 调用失败: " + response.getStatusCode()
);
}
)
.build();
}
}
3. 性能优化
- 连接池配置:合理配置连接池大小
- 超时设置:设置合理的超时时间
- 缓存响应:对不经常变化的数据进行缓存
@Configuration
public class PerformanceConfig {
@Bean
public RestClient restClient() {
// 配置连接池
ConnectionProvider connectionProvider = ConnectionProvider.builder("http-pool")
.maxConnections(100) // 最大连接数
.maxIdleTime(Duration.ofSeconds(20)) // 最大空闲时间
.maxLifeTime(Duration.ofSeconds(60)) // 最大生存时间
.pendingAcquireTimeout(Duration.ofSeconds(10)) // 获取连接超时
.build();
HttpClient httpClient = HttpClient.create(connectionProvider)
.responseTimeout(Duration.ofSeconds(10));
ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);
return RestClient.builder()
.baseUrl("http://api.example.com")
.clientConnector(connector)
.build();
}
}
六、总结
声明式 HTTP 客户端 @HttpExchange 是 Spring Framework 7.0 引入的强大功能,主要优势:
- 代码简洁:代码量减少 60% 以上,这提升不是一点半点
- 类型安全:编译时检查,减少运行时错误,用起来放心
- 易于维护:接口定义清晰,易于理解和维护,团队协作更方便
- 功能强大:支持所有 HTTP 方法、参数类型、认证方式等,基本啥都能干
使用建议:
- 入门:从简单的 GET 请求开始,逐步学习;别着急,慢慢来
- 进阶:掌握参数处理、配置、错误处理;这些是核心功能,得熟练掌握
- 精通:掌握高级用法、性能优化、最佳实践;用好了性能提升明显
反正鹏磊觉得这功能确实实用,特别是做微服务的时候,调用其他服务方便多了。代码简洁,维护起来也省事。
好了,今天就聊到这;下一篇咱详细说说 GraalVM 原生镜像编译与性能优化,包括怎么用 GraalVM 编译原生镜像,提升启动速度和性能。兄弟们有啥问题可以在评论区留言,鹏磊看到会回复的。