添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
@RestController
@SpringBootApplication
public class WebfluxBilibiliApplication {
    public static void main(String[] args) {
        SpringApplication.run(WebfluxBilibiliApplication.class, args);
    @RequestMapping("/greeting")
    public Mono<String> greeting(){
        return Mono.just("hello world");
$ curl localhost:8080/greeting
hello world

Server-Sent Event(SSE)

SSE vs WebSocket

  • SSE 是单向的。----股票交易市场
  • WebSocket是双向的。 双方可以互相发送数据,直到任意一方关闭链接。 —聊天工具
    @RequestMapping("/sse")
    public Flux<String> sse(){
        //每一秒中推送一条数据
        return Flux.interval(Duration.ofMillis(1000)).map(val -> "->" + val);
$ curl localhost:8080/sse
->0->1->2->3->4->5->6->7->8->9->10->11->12->13  ###ctrl+c 终止命令

修改上述接口

指定mediaType= "text/event-stream"

 @RequestMapping(value = "/sse",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> sse(){
        //每一秒中推送一条数据
        return Flux.interval(Duration.ofMillis(1000)).map(val -> "->" + val);
$ curl localhost:8080/sse
data:->0
data:->1
data:->2

sse属性

https://docs.kilvn.com/JavaScript-Standards-Reference-Guide/htmlapi/eventsource.html

  • id: 字符串,默认为空
  • event: 事件,默认为空
  • data: 传递的数据,为字符串或任意对象
  • retry:
   @RequestMapping(value = "/sse")
    public Flux<ServerSentEvent<String>> sse(){
        return   Flux.interval(Duration.ofMillis(1000))
                .map(val -> ServerSentEvent.<String>builder()
                        .id(UUID.randomUUID().toString())
                        .event("TEST_EVENT")
                        .data(val.toString())
                        .build()
$ curl localhost:8080/sse
id:8e931afa-648d-4d07-8642-07364297cb37
event:TEST_EVENT
data:0
id:1de714ef-9937-467f-a1f9-462b8fd089cb
event:TEST_EVENT
data:1

EventSource

前端(浏览器)通过EventSource组件来接收服务端推送来的消息。

只需在前文中的接口上添加:@CrossOrigin("*") 允许跨域即可。

<script type="text/javascript">
	if (!!window.EventSource) {
		// 建立连接
  		var source = new EventSource("http://localhost:8080/sse");
  		0,相当于常量EventSource.CONNECTING,表示连接还未建立,或者连接断线。
		1,相当于常量EventSource.OPEN,表示连接已经建立,可以接受数据。
		2,相当于常量EventSource.CLOSED,表示连接已断,且不会重连。
  		console.info(source.readyState);
  		source.onopen = function(event) {
		  console.info("open");
        //监听指定的时间名称
		source.addEventListener("TEST_EVENT", function(event) {
		  var data = event.data;
		  var origin = event.origin; //服务器端URL的域名部分,即协议、域名和端口。
		  var lastEventId = event.lastEventId; //数据的编号,由服务器端发送。
		  console.info(origin+"->"+lastEventId +"->"+data);
		}, false);
		source.onerror = function(event) {
		  console.info(error);
		//source.close(); //close方法用于关闭连接。
</script>

WebFlux vs SpringMVC

响应式和非阻塞通常来讲也不会使应用运行的更快。相反,非阻塞方式要求做更多的事情,而且还会稍微增加一些必要的处理时间。也就是说,还可能稍稍变慢一点,what,那为啥还要用它呢?响应式和非阻塞的关键好处是,在使用很少固定数目的线程和较少的内存情况下的扩展能力

服务端搭建

  @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Employee {
        private int id;
        private String name;
    private List<Employee> list;
        list = new ArrayList<>();
        IntStream.rangeClosed(1, 100).forEach(index ->
                list.add(new Employee(index, "name_" + index))
    private void dosth() {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
    @RequestMapping(value = "/flux")
    public Flux<Employee> findAll() {
        LocalDateTime start = LocalDateTime.now();
        Flux<Employee> flux = Flux.range(1, 5).map(val ->
                    dosth();
                    return list.stream().filter(employee -> employee.getId() == val).findFirst().get();
        System.out.println("flux::" + Duration.between(start, LocalDateTime.now()).toMillis() + "ms");
        return flux;
    @RequestMapping(value = "/rest")
    public List<Employee> findAll2() {
        LocalDateTime start = LocalDateTime.now();
        List<Employee> ret = IntStream.range(1, 5).mapToObj(val ->
                    dosth();
                    return list.stream().filter(employee -> employee.getId() == val).findFirst().get();
        ).collect(Collectors.toList());
        System.out.println("rest::" + Duration.between(start, LocalDateTime.now()).toMillis() + "ms");
        return ret;

浏览器请求

浏览器结果

flux::4ms
rest::4040ms

使用webflux的前台响应时间反而比rest更耗时,
但是后台响应处理更为迅速。

WebClient

WebClient是基于Reactor实现的,非阻塞的。而RestTemplate是阻塞的。

Flux<WebfluxBilibiliApplication.Employee> flux = WebClient.create("http://localhost:8080/flux")
    .get()
    .retrieve()
    .bodyToFlux(WebfluxBilibiliApplication.Employee.class);

Post传参

WebfluxBilibiliApplication.Employee employee = new WebfluxBilibiliApplication.Employee(999, "jhs");
WebClient.create("http://localhost:8080/save")
    .post()
    .body(Mono.just(employee), WebfluxBilibiliApplication.Employee.class)
    .retrieve()
    .bodyToFlux(WebfluxBilibiliApplication.Employee.class);

Form Data

MultiValueMap<String, String> formData = ... ;
Mono<Void> result = client.post()
        .uri("/path", id)
        .bodyValue(formData)
        .retrieve()
        .bodyToMono(Void.class);
///方法2
import static org.springframework.web.reactive.function.BodyInserters.*;
Mono<Void> result = client.post()
        .uri("/path", id)
        .body(fromFormData("k1", "v1").with("k2", "v2"))
        .retrieve()
        .bodyToMono(Void.class);

Multipart Data

MultipartBodyBuilder builder = new MultipartBodyBuilder();
builder.part("fieldPart", "fieldValue");
builder.part("filePart1", new FileSystemResource("...logo.png"));
builder.part("jsonPart", new Person("Jason"));
builder.part("myPart", part); // Part from a server request
MultiValueMap<String, HttpEntity<?>> parts = builder.build();
MultipartBodyBuilder builder = ...;
Mono<Void> result = client.post()
        .uri("/path", id)
        .body(builder.build())
        .retrieve()
        .bodyToMono(Void.class);

Client Filters

WebClient client = WebClient.builder() .filter((request, next) -> { ClientRequest filtered = ClientRequest.from(request) .header("foo", "bar") .build(); return next.exchange(filtered); .build(); import static org.springframework.web.reactive.function.client.ExchangeFilterFunctions.basicAuthentication; WebClient client = WebClient.builder() .filter(basicAuthentication("user", "password")) .build(); WebClient client = WebClient.builder() .filter((request, next) -> { Optional<Object> usr = request.attribute("myAttribute"); // ... .build(); client.get().uri("https://example.org/") .attribute("myAttribute", "...") .retrieve() .bodyToMono(Void.class);

添加filter

import static org.springframework.web.reactive.function.client.ExchangeFilterFunctions.basicAuthentication;
WebClient client = webClient.mutate()
        .filters(filterList -> {
            filterList.add(0, basicAuthentication("user", "password"));
        .build();
				
SpringWebfluxSpringFramework5.0添加的新功能,WebFlux本身追随当下最火的Reactive Programming而诞生的框架,那么本篇就来简述一下这个框架到底是做什么的 一、关于WebFlux   我们知道传统的Web框架,比如说:struts2,springmvc等都是基于Servlet API与Servlet容器基础之上运行的,在Servlet3.1之后才有了异步非阻塞的支持。而WebFlux是一个典型非阻塞异步的框架,它的核心是基于Reactor的相关API实
> 是Spring Framework提供的一种用户构建响应式Web应用程序的模块。它基于Reactive Streams标准,并使用了Reactor库来实现非阻塞、异步的编程模型 > 与传统的Spring MVC相比,Spring WebFlux采用了一种基于事件驱动的架构,可以处理更高的并发请求和负载。它不再依赖于Servlet容器,而是使用自己的服务器,例如Netty或Undertow,以实现异步、高效的请求处理
Spring WebFlux是随Spring 5推出的是一个响应式编程和异步非阻塞的Web开发框架, 它与Spring MVC不同,它不需要Servlet API,完全异步和非阻塞,以Reactor为基础实现响应式编程。 1.1异步编程与同步编程的区别? 了解Spring WebFlux首先先了解异步非阻塞与传统的同步堵塞式有什么区别? 这里我简单的对这两个打个比方: 同步编程: 同步也就是A节点发送了一个消息给B节点,等待收到 B 节点的...
大家都知道,Spring Framework 是 Java/Spring 应用程序跨平台开发框架,也是 Java EE(Java Enterprise Edition) 轻量级框架,其 Spring 平台为 Java 开发者提供了全面的基础设施支持,虽然 Spring 基础组件的代码是轻量级,但其配置依旧是重量级的。 那是怎么解决了呢?当然是 Spring Boot,Spring Boo... 如果有关注我公众号文章的同学就会发现,最近我不定时转发了一些比较好的WebFlux的文章,因为我最近在学。 我之前也说过,学习一项技术之前,先要了解为什么要学这项技术。其实这次学习WebFlux也没有多大的原生动力,主要是在我们组内会轮流做一次技术分享,而我又不知道分享什么比较好... 之前在初学大数据相关的知识,但是这一块的时间线会拉得比较长,感觉赶不及小...
今天我们开始来学习下 WebFlux,为什么突然要学这个东西? 因为我之前是想学习 Spring Cloud Gateway 来着,然后发现它是基于 Spring5.0+SpringBoot2.0+WebFlux等技术开发的。所以学之前才要来简单了解下 WebFlux 技术。 然后要学习 WebFlux 时我发现又需要 Java 8 中的函数式编程、Stream 流等技术作为前置知识。环环相扣啊,套娃一样。 所以前面还有两篇学习的文章:来系统学习下 lambda 表达式吧和来一起学习下 Java 8 的 S
1、SpringWebflux 介绍 (1)是 Spring5 添加新的模块,用于 web 开发的,功能和 SpringMVC 类似的,Webflux 使用 当前一种比较流行响应式编程出现的框架。 (2)使用传统 web 框架,比如 SpringMVC,这些基于 Servlet 容器,Webflux 是一种异步非阻 塞的框架,异步非阻塞的框架在 Servlet3.1 以后才支持,核心是基于 Reactor 的相关 API 实现 (3)解释什么是异步非阻塞 异步和同步 非阻塞和阻塞 ** 上面都是针