ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2019-10-12 05:21:51  阅读:216  来源: 互联网

标签:spring-webflux spring spring-boot


我想有一个http客户端从Spring Boot不响应的应用程序调用其他微服务.由于将不使用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方法调用中传递带有协议和端口的完整url:

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

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

解决方法:

没错,WebClient.Builder不是线程安全的.

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

它应该看起来像这样:

@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.如果您的应用程序还有其他需求(用于身份验证的自定义标头等),那么您也可以在构建器上或根据每个请求执行此操作.

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

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

标签:spring-webflux,spring,spring-boot
来源: https://codeday.me/bug/20191012/1898092.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有