【问题标题】:Spring Boot WebClient Builder initialization in ServiceImpl ConstructorServiceImpl 构造函数中的 Spring Boot WebClient Builder 初始化
【发布时间】:2021-02-12 03:31:33
【问题描述】:

我正在尝试遵循使用 WebClient Builder 自动装配 Webclient 的最佳实践,但有点困惑。

这是我的主要应用程序,我正在其中生成一个 Webclient Builder 并将其自动装配到我的一个服务类中

 @SpringBootApplication
    public class MyApplication {
        @Bean
        public WebClient.Builder getWebClientBuilder() {
            return WebClient.builder();
        }
    
        public static void main(String[] args) {
            SpringApplication.run(MyApplication.class, args);
        }}


ServiceImpl Class

    public class MyServiceImpl implements MyService {
        private static final String API_MIME_TYPE = "application/json";
        private static final String API_BASE_URL = "http://localhost:8080";
        private static final String USER_AGENT = "Spring 5 WebClient";
        private static final Logger logger = LoggerFactory.getLogger(MyServiceImpl.class);
    
        @Autowired
        private WebClient.Builder webClientBuilder;
    
        @Override
        public Mono<Issue> createIssue(Fields field) {
            return webClientBuilder.build()
                    .post()
                    .uri("/rest/api/")
                    .body(Mono.just(field), Fields.class)
                    .retrieve()
                    .bodyToMono(Issue.class);
        }}

我正在尝试使用 BaseURl、DefaultHeader 等构建 webClientBuilder。我尝试在 MyServiceImpl 构造函数中对其进行初始化,但不确定它是否正确。

public MyServiceImpl() {
            this.webClientBuilder
                    .baseUrl(API_BASE_URL).defaultHeader(HttpHeaders.CONTENT_TYPE, API_MIME_TYPE)
                    .defaultHeader(HttpHeaders.USER_AGENT, USER_AGENT)
                    .build();
        } 

我这样做是正确的还是有更好的方法。

目前我有 2 个 ServiceImpls 来调用不同的 API,这就是我尝试在服务本身中设置“baseurl”和其他默认值的原因。

请帮忙。 TIA

【问题讨论】:

    标签: java spring-boot spring-webflux spring-webclient


    【解决方案1】:

    通常,您的方法是这样的:

    @SpringBootApplication
    public class MyApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(MyApplication.class, args);
        }
    }
    
    @Configuration
    public class MyApplicationConfiguration {
        
        @Bean
        public WebClient myWebClient(WebClient.Builder webClientBuilder) {
            return webClientBuilder
                    .baseUrl(API_BASE_URL)
                    .defaultHeader(HttpHeaders.CONTENT_TYPE, API_MIME_TYPE)
                    .defaultHeader(HttpHeaders.USER_AGENT, USER_AGENT)
                    .build();
        }
    }
    
    @Service
    public class MySericeImpl implements MyService {
    
        @Autowired
        private WebClient myWebClient;
    
        @Override
        public Mono<Issue> createIssue(Fields field) {
            return myWebClient
                    .post()
                    .uri("/rest/api/")
                    .body(Mono.just(field), Fields.class)
                    .retrieve()
                    .bodyToMono(Issue.class);
        }
     }
    

    要记住的关键是WebClient.Builder 已经为您预先配置并且 Bean 已经创建。所以你只需要自动装配它,调整配置并构建最终的WebClient

    也可以使用其他方法来配置它。有 3 种主要方法可以自定义 WebClient。更多详情见官方文档https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-webclient


    编辑以使用更多 API - 配置多个 WebClient 并将它们自动装配到适当的服务类中。

    @Configuration
    public class MyApplicationConfiguration {
        
        @Bean
        public WebClient myWebClientForApi1(WebClient.Builder webClientBuilder) {
            return webClientBuilder
                    .clone()
                    .baseUrl(API_1_BASE_URL)
                    .defaultHeader(HttpHeaders.CONTENT_TYPE, API_MIME_TYPE)
                    .defaultHeader(HttpHeaders.USER_AGENT, USER_AGENT)
                    .build();
        }
    
        @Bean
        public WebClient myWebClientForApi2(WebClient.Builder webClientBuilder) {
            return webClientBuilder
                    .clone()
                    .baseUrl(API_2_BASE_URL)
                    .defaultHeader(HttpHeaders.CONTENT_TYPE, API_MIME_TYPE)
                    .build();
        }
    }
    

    【讨论】:

    • 谢谢@raestio(更新了我的问题)-实际上我有 2 个 ServiceImpls 来调用 2 个不同的 RestApis,所以我尝试在 serviceimpl 本身中初始化 baseurl。目前我正在尝试在同一个应用程序中使用两种服务的单体方式。接下来是我想将它作为微服务尝试,然后这种方法就可以了。
    • 没问题,我也更新了答案。您可以使用 'clone()' 方法并配置多个 WebClients 而无需更改另一个。然后,您可以使用“@Qualifier”在服务类中自动连接您想要的。无需在服务类中创建 WebClient。这是配置,所以最好将它放在@Configuration 类中。更清晰,更接近单一职责原则。
    • 是的,方法是将它们设置在您创建 WebClients 的位置,即 Config 类 - MyApplicationConfiguration。因此,您可以选择带有 @Value 注释的属性。在旁注中,通常您不希望直接包含密码。即使它被编码,它也没有被加密,所以你仍然可以看到密码值。你不想要它,除非它只是一些个人项目,而不是每个人都能看到的公司。您可以对其进行加密,也可以为云开发应用程序并使用例如Kubernetes,你可以使用 Secrets。
    • 谢谢伙计,是的,我确实会在不久的将来使用 Kubernetes,我目前也在为 CKAD 做准备:)。我曾使用过 HTTPClient 库和 Rest Template,但我对这个 Webclient 部分非常陌生,并且遇到了很多困难。实际上,我正在研究 Servicenow API,例如获取、创建、更新。我有几个问题,我计划本周在 Stackover 流程​​中发布。将其粘贴到我们的对话中
    • 乐于助人:)
    猜你喜欢
    • 2020-02-13
    • 1970-01-01
    • 2015-03-19
    • 1970-01-01
    • 2013-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多