WebClient: Spring的新的HTTP反应式客户端 - spring.io


今天,我们将研究一个多功能的,方便的,花哨的HTTP客户端WebClient。
HTTP服务是常见的数据源。Web是HTTP可伸缩性和弹性的存在证明,在构建网络服务时,它非常有力地证明了对HTTP约束(如REST)的吸引力。
有一些很棒的库(例如Apache HttpComponents ClientOkHttp)以相同的方式工作。WebClient是在Spring Webflux中使用基于Netty的非阻塞HTTP客户端.
WebClient是反应性的,无阻塞的,用来替代RestTemplate。因为它是非阻塞的:用于发出网络请求的客户端线程不会挂断以等待网络服务响应。这意味着更好的可伸缩性,它使用了Reactive Streams API,使编写变得更加容易.WebClient可以与任何旧的HTTP端点进行通信.
 
使用WebClient需要引入依赖:org.springframework.boot : spring-boot-starter-webflux
下面是WebClient代码演示的功能:

  • 使用支持Spring Initializr的HTTP API初始化了一个新项目
  • 它使用Spring API检索所有活动的开源Spring项目

package bootiful.httpclient.webclient;

import lombok.ToString;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;

import static java.nio.file.StandardOpenOption.CREATE;

@EnableAsync
@SpringBootApplication
public class BootifulApplication {

    public static void main(String[] args) {
        SpringApplication.run(BootifulApplication.class, args);
    }

    @Bean
    WebClient webClient(WebClient.Builder builder) {
        return builder//
                .filter(
//
                        (clientRequest, exchangeFunction) -> exchangeFunction
//
                                .exchange(clientRequest)
//
                                .doOnNext(response -> System.out.println(
"got a WebClient response: " + response))//
                )
//
                .build();
    }

    @Bean
    ApplicationListener<ApplicationReadyEvent> ready(@Value(
"file://${user.home}/Desktop/output.zip") Path output,
            WebClient client) {

        return event -> {

            
// initialize a new Spring Boot project .zip archive
            Mono<DataBuffer> db = client.get()
//
                    .uri(URI.create(
"https://start.spring.io/starter.zip"))//
                    .accept(MediaType.APPLICATION_OCTET_STREAM)
//
                    .retrieve()
//
                    .bodyToMono(DataBuffer.class);

            
// gets written out to ~/output.zip
            Mono<Boolean> write = DataBufferUtils.write(db, output, CREATE).thenReturn(true);

            
// enumerate all the active Spring projects using the
            
// JSON API while we're at it...
            Mono<ProjectsResponse> json = client
//
                    .get()
//
                    .uri(URI.create(
"https://spring.io/api/projects"))//
                    .retrieve()
//
                    .bodyToMono(ProjectsResponse.class);

            
// look ma! No threading code! this will launch both network
            
// calls (the .zip and the json) at the same time
            Mono.zip(write, json).subscribe(tuple -> enumerate(tuple.getT2()));
        };
    }

    private void enumerate(ProjectsResponse pr) {
        pr._embedded
//
                .projects
//
                        .stream()
//
                        .filter(p -> p.status.equalsIgnoreCase(
"active")) //
                        .forEach(project -> System.out.println(project.toString()));
    }

}

@ToString
class ProjectsResponse {

    public Embedded _embedded = new Embedded();

    @ToString
    public static class Project {

        public String name, slug, status, repositoryUrl;

    }

    @ToString
    public static class Embedded {

        public Collection<Project> projects = new ArrayList<>();

    }

}


您想引入WebClient,但不想使用其余的反应式Web堆栈,则需要告诉Spring Boot。否则,Spring Boot将尝试建立基于Netty的Spring Webflux环境。
需要以下配置application.properties:
spring.main.web-application-type=none