gpt4 book ai didi

Spring Boot WebClient.Builder bean 在传统 servlet 多线程应用程序中的使用

转载 作者:行者123 更新时间:2023-12-03 15:30:53 25 4
gpt4 key购买 nike

我想要一个 http 客户端从 Spring Boot 调用其他微服务无 react 应用。由于 RestTemplate 将被弃用,我尝试使用 WebClient.Builder 和 WebClient。虽然我不确定线程​​安全。这里的例子:

@Service
public class MyService{
@Autowired
WebClient.Builder webClientBuilder;

public VenueDTO serviceMethod(){
//!!! This is not thread safe !!!
WebClient webClient = webClientBuilder.baseUrl("http://localhost:8000").build();

VenueDTO venueDTO = webClient.get().uri("/api/venue/{id}", bodDTO.getBusinessOutletId()).
retrieve().bodyToMono(VenueDTO.class).
blockOptional(Duration.ofMillis(1000)).
orElseThrow(() -> new BadRequestException(venueNotFound));
return VenueDTO;
}
}

本例中的 serviceMethod() 将从几个线程中调用,而 webClientBuilder 是单个 bean 实例。 WebClient.Builder 类包含状态:baseUrl,这似乎不是线程安全的,因为很少有线程可以同时调用此状态更新。同时,WebClient 本身似乎是线程安全的,如 Right way to use Spring WebClient in multi-thread environment 的回答中所述

我应该使用 https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-webclient.html 中提到的 WebClient.Builder bean吗?

Spring Boot creates and pre-configures a WebClient.Builder for you; it is strongly advised to inject it in your components and use it to create WebClient instances.



我看到的解决方法之一是创建 WebClient 而不将任何状态传递给构建器,而不是:
WebClient webClient = webClientBuilder.baseUrl("http://localhost:8000").build();

我会做:
WebClient webClient = webClientBuilder.build();

并在 uri 方法调用中传递带有协议(protocol)和端口的完整 url:
webClient.get().uri("full url here", MyDTO.class)

在我的情况下使用它的正确方法是什么?

最佳答案

你说得对,WebClient.Builder不是线程安全的。

Spring Boot 正在创建 WebClient.Builder作为原型(prototype) bean,因此您将获得每个注入(inject)点的新实例。就您而言,我认为您的组件似乎有点奇怪。

它应该看起来像这样:

@Service
public class MyService{

private final WebClient webClient;

public MyService(WebClient.Builder webClientBuilder) {
this.webClient = webClientBuilder.baseUrl("http://localhost:8000").build();
}

public VenueDTO serviceMethod(){
VenueDTO venueDTO = webClient.get().uri("/api/venue/{id}", bodDTO.getBusinessOutletId()).
retrieve().bodyToMono(VenueDTO.class).
blockOptional(Duration.ofMillis(1000)).
orElseThrow(() -> new BadRequestException(venueNotFound));
return VenueDTO;
}
}

现在我猜这是一个代码片段,您的应用程序可能有不同的约束。

如果您的应用程序需要经常更改基本 URL,那么我认为您应该停止在构建器上配置它并传递问题中提到的完整 URL。如果您的应用程序有其他需求(用于身份验证的自定义 header 等),那么您也可以在构建器或每个请求的基础上执行此操作。

一般来说,您应该尝试构建一个 WebClient每个组件的实例,因为为每个请求重新创建它是非常浪费的。

如果您的应用程序有非常具体的约束并且确实需要创建不同的实例,那么您可以随时调用 webClientBuilder.clone()并获得一个新的构建器实例,您可以对其进行变异,而不会出现线程安全问题。

关于Spring Boot WebClient.Builder bean 在传统 servlet 多线程应用程序中的使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54136085/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com