Spring Boot WebClient.Builder bean在传统servlet多线程应用程序中的用法 [英] Spring Boot WebClient.Builder bean usage in traditional servlet multi threaded application

查看:205
本文介绍了Spring Boot WebClient.Builder bean在传统servlet多线程应用程序中的用法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想让一个http客户端从Spring Boot notactive 应用程序调用其他微服务.由于将不使用RestTemplate,因此我尝试使用WebClient.Builder和WebClient.虽然我不确定线程​​安全性.例如:

I would like to have a http client to call other microservice from Spring Boot not reactive application. Because of RestTemplate will be deprecated I tried to use WebClient.Builder and WebClient. Though I not sure about thread safety. Here example:

@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本身似乎是线程安全的.在多线程环境中使用Spring WebClient的正确方法

我应该使用 https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-webclient.html

Spring Boot为您创建并预配置了WebClient.Builder;它 强烈建议将其注入您的组件中并使用它来 创建WebClient实例.

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而不将任何状态传递给生成器,因此代替:

One of workaround options I see is to create WebClient without any state passed to builder so instead of:

WebClient webClient = webClientBuilder.baseUrl("http://localhost:8000").build();

我会做的:

WebClient webClient = webClientBuilder.build();

并在uri方法调用中传递带有协议和端口的完整url:

and pass full url with protocol and port in uri method call:

webClient.get().uri("full url here", MyDTO.class)

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

What is the proper way to use it in my case?

推荐答案

您是对的,WebClient.Builder不是线程安全的.

You're right, WebClient.Builder is not thread-safe.

Spring Boot正在将WebClient.Builder创建为原型bean,因此您将为每个注入点获得一个新实例.在您看来,您的组件在我看来似乎有些奇怪.

Spring Boot is creating WebClient.Builder as a prototype bean, so you'll get a new instance for each injection point. In your case, your component seems a bit strange in my opinion.

它应该看起来像这样:

@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;
    }
}

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

Now I guess this is a code snippet and your application may have different constraints.

如果您的应用程序需要经常更改基本URL,那么我认为您应该停止在构建器上对其进行配置,并按照问题中的说明传递完整的URL.如果您的应用程序有其他需求(用于身份验证的自定义标头等),那么您也可以在构建器上或根据每个请求进行此操作.

If your application needs to change the base URL often, then I think you should stop configuring it on the builder and pass the full URL as mentioned in your question. If your application has other needs (custom headers for authentication, etc), then you can also do that on the builder or on a per request basis.

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

In general, you should try and build a single WebClient instance per component, as recreating it for each request is quite wasteful.

如果您的应用程序具有非常特定的约束,并且确实需要创建其他实例,那么您始终可以调用webClientBuilder.clone()并获取一个可以更改的构建器新实例,而不会出现线程安全问题.

In case your application has very specific constraints and really needs to create different instances, then you can always call webClientBuilder.clone() and get a new instance of the builder that you can mutate, without the thread safety issues.

这篇关于Spring Boot WebClient.Builder bean在传统servlet多线程应用程序中的用法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆