响应式web(四):使用Netty作为web容器,基于注解的WebFlux阻塞式与响应式实现
生活随笔
收集整理的這篇文章主要介紹了
响应式web(四):使用Netty作为web容器,基于注解的WebFlux阻塞式与响应式实现
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
目錄
使用 WebFlux,針對IO密集度比較高的系統(tǒng),性能會有提升。
- 使用 Netty 作為 web 容器:注釋掉spring-boot-starter-web,啟動就默認用的 netty 而不是 tomcat 了
- 基于注解的 WebFlux 阻塞式與響應(yīng)式實現(xiàn)
- WebFlux + SSE 服務(wù)器推:下面的案例3
- WebFlux 中的 ServerHttpRequest 與 SpringMVC 的區(qū)別
源碼地址
GitHub 地址:https://github.com/HanquanHq/TestReactive
運行效果
本地運行項目后,瀏覽器輸入:
案例1:http://127.0.0.1:8080/person
控制臺輸出:
案例2:http://127.0.0.1:8080/person/xxoo?name=Tom
控制臺輸出:
案例3:http://127.0.0.1:8080/person/sse
實現(xiàn)了 WebFlux + SSE 服務(wù)器推,不用刷新頁面,也能實時拿到數(shù)據(jù),原理類似于瀏覽器下載文件。
下面這9條數(shù)據(jù),不是一次加載出來的,是逐個輸出的。
控制臺輸出:
1. sub is: reactor.core.publisher.FluxIterable$IterableSubscription@4ec8ff31 3. data is: haha, 1 3. data is: haha, 2 3. data is: haha, 3 3. data is: haha, 4 3. data is: haha, 5 3. data is: haha, 6 3. data is: haha, 7 3. data is: haha, 8 3. data is: haha, 9 doOnComplete,全部完成了!這里傳一個新線程附:代碼
目錄結(jié)構(gòu)
PersonController.java(重點)
package com.mashibing.admin.controller;import com.mashibing.admin.service.PersonService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.server.WebSession; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono;import java.util.Random; import java.util.stream.IntStream;// 使用WebFlux,針對IO密集度比較高的系統(tǒng),性能會有提升。 @RestController @RequestMapping("/person") public class PersonController {@AutowiredPersonService personService;@GetMapping("")Mono<Object> get() {System.out.println("=========here get=====");Mono<Object> mono = Mono.create(sink -> {//組裝數(shù)據(jù)序列sink.success(personService.getPerson());}).doOnSubscribe(sub -> {//訂閱數(shù)據(jù)System.out.println("1. doOnSubscribe..." + sub);}).doOnNext(data -> {//得到數(shù)據(jù)System.out.println("2. data:" + data);}).doOnSuccess(onSuccess -> {//整體完成System.out.println("3. onSuccess:" + onSuccess);});System.out.println("before return, mono: " + mono);// 得到一個包裝的數(shù)據(jù)序列,return給了容器// 容器拿到這個序列,再去執(zhí)行序列里的方法// 這和 ajax 很像// 1. 寫回調(diào)接口,讓b調(diào)用// 2. 將方法傳過去,看起來像是異步,實質(zhì)上,阻塞過程在容器內(nèi)部// 并不是提高效率,只是將阻塞延后System.out.println("return方法線程名稱:" + Thread.currentThread().getName());return mono; // 組織數(shù)據(jù)的過程,是netty容器做的,獲取數(shù)據(jù)的過程不依賴controller了}@GetMapping("xxoo")//serverHttpRequest是webFlux特有的,用法也不一樣//拓展思維,SpringCloud Gateway函數(shù)式,比zuul的性能高,底層是基于netty的Mono<Object> get01(String name, ServerHttpRequest serverHttpRequest, WebSession webSession) {System.out.println("In get01, name = " + name);System.out.println("In get01, serverHttpRequest = " + serverHttpRequest);//org.springframework.http.server.reactive.ReactorServerHttpRequestSystem.out.println("In get01, headers = " + serverHttpRequest.getHeaders());// [Host:"127.0.0.1:8080", User-Agent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0", ...System.out.println("In get01, parameters = " + serverHttpRequest.getQueryParams().get("name"));//[gongluyang]// session 的使用方法if (StringUtils.isEmpty(webSession.getAttribute("code"))) {System.out.println("第一次請求,我要set session 了");webSession.getAttributes().put("code", 111222333);}return Mono.just("me me da!");}// 不引入 spring-webmvc,僅使用 netty 實現(xiàn)@GetMapping(value = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<String> sse() {Flux<String> flux = Flux.fromStream(IntStream.range(1, 10).mapToObj(i -> {// map 是映射,理解為遍歷,但是不是遍歷try {Thread.sleep(new Random().nextInt(3000));} catch (InterruptedException e) {e.printStackTrace();}return "haha, " + i;})).doOnSubscribe(sub -> {System.out.println("1. sub is: " + sub);// reactor.core.publisher.FluxIterable$IterableSubscription}).doOnComplete(() -> {System.out.println("doOnComplete,全部完成了!這里傳一個新線程");}).doOnNext(data -> {System.out.println("3. data is: " + data);});return flux;} }Person.java
package com.mashibing.admin.pojo;public class Person {int id;String name;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Person{" +"id=" + id +", name='" + name + '\'' +'}';} }PersonService.java
package com.mashibing.admin.service;import com.mashibing.admin.pojo.Person; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Service; import reactor.core.publisher.Flux;import java.util.concurrent.ConcurrentHashMap;@Service public class PersonService {static ConcurrentHashMap<Integer, Person> map = new ConcurrentHashMap();static {for (int i = 0; i < 100; i++) {Person person = new Person();person.setId(i);person.setName("person" + i);map.put(i, person);}}public Person getPerson() {try {System.out.println("getPerson線程名稱:" + Thread.currentThread().getName());Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("getPerson(): " + map.get(1));return map.get(1);}public Flux<Person> getPersons() {// 需要讓數(shù)據(jù)自己變成響應(yīng)式的,我們關(guān)注的是前后端的響應(yīng)式Flux<Person> personFlux = Flux.fromIterable(map.values());return personFlux;}}TestReactiveApplication.java
package com.mashibing.admin;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication public class TestReactiveApplication {public static void main(String[] args) {SpringApplication.run(TestReactiveApplication.class, args);} }pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.1.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>demo</artifactId><version>0.0.1-SNAPSHOT</version><name>TeatReactive</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies> <!-- 注釋掉這個,啟動就默認用的 netty 而不是 tomcat 了--> <!-- <dependency>--> <!-- <groupId>org.springframework.boot</groupId>--> <!-- <artifactId>spring-boot-starter-web</artifactId>--> <!-- </dependency>--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency><dependency><groupId>io.projectreactor</groupId><artifactId>reactor-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>總結(jié)
以上是生活随笔為你收集整理的响应式web(四):使用Netty作为web容器,基于注解的WebFlux阻塞式与响应式实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: P8-07-16 使用 Jenkins
- 下一篇: P8实战(四):多种分布式锁实现