一、創建項目
這裏我使用IDEA快速創建基於SpringBoot的工程,當然你也可以選spring.io 創建再導入到IDEA 中。
要創建WebFlux 項目,必須勾選ReactiveWeb而不是傳統的Web ,這裏爲了簡化代碼使用到了Lombok。
項目創建完後目錄:
POM 依賴,這裏IDEA 自動給項目加上了spring-boot-starter-webflux。完整依賴如下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
二、編寫Controller
從序篇 可知道,編寫WebFlux 的Controller 可以沿用SpringMVC 的那一套,但是返回結果需要改成Mono或者Flux。
創建一個mono 接口,返回hello webflux,這裏的Mono.just()方法會發射一個元素,創建響應式的接口就這麼"簡單”。
package com.fine.webfluxquickstart.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
/**
* @author finefine at: 2019-06-01 15:02
*/
@RestController
@RequestMapping("/api/")
public class HelloController {
@GetMapping("mono")
public Mono<String> mono() {
return Mono.just("hello webflux");
}
}
那麼來測試一下,瀏覽器地址輸入 localhost:8080/api/mono
。
其實呢,上面mono接口這種執行模式是同步非阻塞的,也就是Mono產生數據,和Mono與Http 之間的訂閱消費都是在同一個線程。
那既然這樣,到底是不是在同一個線程中呢,更改代碼證明一下。
package com.fine.webfluxquickstart.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
/**
* @author finefine at: 2019-06-01 15:02
*/
@RestController
@RequestMapping("/api/")
@Slf4j
public class HelloController {
@GetMapping("mono")
public Mono<Object> mono() {
return Mono.create(monoSink -> {
log.info("創建 Mono");
monoSink.success("hello webflux");
})
.doOnSubscribe(subscription -> { //當訂閱者去訂閱發佈者的時候,該方法會調用
log.info("{}",subscription);
}).doOnNext(o -> { //當訂閱者收到數據時,改方法會調用
log.info("{}",o);
});
}
}
如圖,Mono的創建和消費都是都是在ctor-http-nio-2 這個線程中,仔細看看這log的順序,你會發現訂閱動作在創建動作之前,最後是消費,那麼爲什麼會這樣呢?這個先留到後面講,感興趣的可以先去了解一下。
之前提到了Mono 最多發射一個數據,Flux 可以發射多個數據,那麼來寫個Flux看看吧。
package com.fine.webfluxquickstart.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
/**
* @author finefine at: 2019-06-01 15:02
*/
@RestController
@RequestMapping("/api/")
@Slf4j
public class HelloController {
@GetMapping("mono")
public Mono<Object> mono() {
return Mono.create(monoSink -> {
log.info("創建 Mono");
monoSink.success("hello webflux");
})
.doOnSubscribe(subscription -> {
log.info("{}", subscription);
}).doOnNext(o -> {
log.info("{}", o);
});
}
@GetMapping("flux")
public Flux<String> flux() {
return Flux.just("hello","webflux","spring","boot");
}
}
這裏Flux發射了4個數據,來看下結果:
三、總結
WebFlux 應用中,所有數據都應該以Mono、Flux的形式表示,這樣才能帶來最好的性能和高吞吐量。Mono和Flux 這兩種數據模型是WebFlux的核心,本片入門教程只是簡單的展示了WebFlux項目的搭建編寫,要學好WebFlux 還需要掌握Reactor(Mono、Flux),其實Reactor 和 Stream 的很多操作都有類似功能,如果你對Java8Stream非常熟悉的話,學習Reactor應該是也是件容易的事情,如果還不掌握Stream 建議先去學好Stream。
QQ羣:577715614
源碼