一、SprinBoot2.x响应式编程简介
简介:讲解什么是reactive响应式编程和使用的好处
1、基础理解:
依赖于事件,事件驱动(Event-driven)
一系列事件称为“流”
异步
非阻塞
1)买奶茶的案例(一个一个等待处理)
2)响应式编程
观察者模式:服务员一直观察后台的情况,然后通知客户
网上的一个例子:
int b= 2;
int c=3
int a = b+c //命令式编程后续b和c变化,都不影响a
b=5;
int b= 2;
int c= 3
int a = b+c //响应式编程中,a的变化,会和b、c的变化而变化(事件驱动)
b=5;
2、官网:https://docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/reference/htmlsingle/#boot-features-webflux
SpingBoot2底层是用spring5,开始支持响应式编程,Spring又是基于Reactor试下响应式。
学习资料
1、reactive-streams学习资料:http://www.reactive-streams.org/
2、web-flux相关资料:https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#spring-webflux
总结:响应式编程,必须每一个阶段都不阻塞,才能提升性能
二、SpringBoot2.x响应式编程webflux介绍
简介:讲解SpringBoot2.x响应式编程介绍 Mono、Flux对象和优缺点
1、Spring WebFlux是Spring Framework 5.0中引入的新的反应式Web框架
与Spring MVC不同,它不需要Servlet API,完全异步和非阻塞,并 通过Reactor项目实现Reactive Streams规范。
RxJava
2、Flux和Mono User List<User>
1)简单业务而言:和其他普通对象差别不大,复杂请求业务,就可以提升性能
2)通俗理解:
Mono 表示的是包含 0 或者 1 个元素的异步序列 (序列理解成流)
mono->单一对象 User redis->用户ID-》唯一的用户Mono<User>
Flux 表示的是包含 0 到 N 个元素的异步序列
flux->数组列表对象 List<User> redis->男性用户->Flux<User>
Flux 和 Mono 之间可以进行转换
3、Spring WebFlux有两种风格:基于功能和基于注解的。基于注解非常接近Spring MVC模型,如以下示例所示:
第一种:
第二种:
“WebFlux.fn”是功能变体,它将路由配置与请求的实际处理分开,如以下示例所示:
@Configuration
public class RoutingConfiguration {
@Bean
public RouterFunction<ServerResponse> monoRouterFunction(UserHandler userHandler) {
return route(GET("/{user}").and(accept(APPLICATION_JSON)), userHandler::getUser)
.andRoute(GET("/{user}/customers").and(accept(APPLICATION_JSON)), userHandler::getUserCustomers)
.andRoute(DELETE("/{user}").and(accept(APPLICATION_JSON)), userHandler::deleteUser);
}
}
@Component
public class UserHandler {
public Mono<ServerResponse> getUser(ServerRequest request) {
// ...
}
public Mono<ServerResponse> getUserCustomers(ServerRequest request) {
// ...
}
public Mono<ServerResponse> deleteUser(ServerRequest request) {
// ...
}
}
4、Spring WebFlux应用程序不严格依赖于Servlet API,因此它们不能作为war文件部署,也不能使用src/main/webapp目录
5、可以整合多个模板引擎
除了REST Web服务外,您还可以使用Spring WebFlux提供动态HTML内容。Spring WebFlux支持各种模板技术,包括Thymeleaf,FreeMarker
三、SpringBoot2.x webflux实战
简介:webflux响应式编程实战
1、WebFlux中,请求和响应不再是WebMVC中的ServletRequest和ServletResponse,而是ServerRequest和ServerResponse
2、加入依赖,如果同时存在sprin g-boot-starter-web,则会优先用spring-boot-starter-web
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itcast</groupId>
<artifactId>Springboot08_A</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
</parent>
<dependencies>
<!-- <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>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
官网说明
测试
1)
2)
3、启动方式默认是Netty,8080端口
Netty:高性能网络框架,异步非阻塞
4、参考:https://spring.io/blog/2016/04/19/understanding-reactive-types
5.模拟数据库实现CRUD
1)service
package com.itcast.demo.service;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Service;
import com.itcast.demo.domain.User;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Service
public class UserService {
//模拟数据库
private static final Map<String,User> map =new HashMap<>();
static{//一创建对象就初始化map
map.put("1", new User("1", "小王1"));
map.put("2", new User("2", "小王2"));
map.put("3", new User("3", "小王3"));
map.put("4", new User("4", "小王4"));
map.put("5", new User("5", "小王5"));
map.put("6", new User("6", "小王6"));
map.put("7", new User("7", "小王7"));
map.put("8", new User("8", "小王8"));
}
//返回所有数据
public Flux<User> list(){
Collection<User> list = UserService.map.values();
return Flux.fromIterable(list);
}
//通过id查出
public Mono<User> getById(final String id){
return Mono.justOrEmpty(UserService.map.get(id));
}
//通过id删除用户
public Mono<User> del(final String id){
return Mono.justOrEmpty(UserService.map.remove(id));
}
}
2)controller
package com.itcast.demo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.itcast.demo.domain.JsonData;
import com.itcast.demo.domain.User;
import com.itcast.demo.service.UserService;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* @作者po
*/
@RestController
@RequestMapping("/api/v1")
public class UserController {
//@Autowired
//private UserService userService;
//通过构造的方式
private final UserService userService;
public UserController(final UserService userService ) {
this.userService=userService;
}
@GetMapping("test")
public Mono<String> Test01() {
return Mono.just("hello Mono");
}
@GetMapping("getById")
public Mono<User> getById(final String id){
return userService.getById(id);
}
@GetMapping("del")
public Mono<User> del(final String id){
return userService.del(id);
}
@GetMapping("list")
public Flux<User> list(){
return userService.list();
}
}
3)访问
4)list
5)del
6)调用list的时候,希望拿到一个值就返回,如何体现这种效果
//import org.springframework.http.MediaType;
//拿到一个值就返回,即2s就返回,produces不配就没有这样的效果
@GetMapping(value="list",produces=MediaType.APPLICATION_STREAM_JSON_VALUE)
public Flux<User> list(){//延迟两秒
return userService.list().delayElements(Duration.ofSeconds(2));
}
应该:服务端的推送(像流水一样)
四、WebFlux客户端WebClient讲解
简介:讲解SpringBoot2.x WebFlux客户端WebClient的介绍和使用
1、反应式客户端
官网地址:https://docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/reference/htmlsingle/#boot-features-webclient
实战
1)在测试
package com.domain;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
public class WebClientTest {
@Test
public void testBase(){
Mono<String> resp = WebClient.create()
.get()
//多个参数也可以直接放到map中,参数名与placeholder对应上即可
.uri("http://localhost:8080/api/v1/getById?id=1") //使用占位符
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(String.class);
System.out.println(resp.block());
}
@Test
public void testPlaceHolder(){
Mono<String> resp = WebClient.create()
.get()
.uri("http://localhost:8080/api/v1/getById?id={id}",1) //使用占位符
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(String.class);
System.out.println(resp.block());
}
}