Spring WebFlux 学习笔记
Spring WebFlux学习
1、Webflux介绍
webflux特性:
非阻塞式:在有限的资源下,提高系统吞吐量和伸缩性,以Reactor为基础实现响应式编程
函数式编程:Spring5框架基于java8函数函数时编程方式实现路由请求
SpingMVC和Spring WebFlux对比
不同点:springmvc采用的是命令式编程,Webflux采用异步响应式编程
2、响应式编程
什么是响应式编程:
响应式编程是一种面向数据流和变化传播的编程范式
电子表格程序就是响应式编程的一个例子。单元格可以包含字面值或类似"=B1+C1"的公式,而包含公式的单元格的值会依据其他单元格的值的变化而变化。
Java8和之前版本
提供观察者模式两个类Observer和Observable
public class ObserverDemo extends Observable {
public static void main(String[] args) {
ObserverDemo observerDemo = new ObserverDemo();
observerDemo.addObserver((o, arg) -> {
System.out.println("发生变化之前");
});
observerDemo.addObserver((o, arg) -> {
System.out.println("发生了变化");
});
observerDemo.setChanged();
observerDemo.notifyObservers();
}
}
在jdk9之后(Observer和Observable就弃用了)使用Flow才是真正的响应式编程
响应式编程(Reactor实现)
1、响应式编程操作中,Reactor是满足Reactive规范框架java
2、Reactor有两个核心类,Mono和Flux,这两个类杜实现了Publisher,提供丰富操作符,Flux对象实现发布者,返回N个元素;Mono实现发布者,返回0或者1个元素
3、Mono和Flux都是数据流的发布者,使用Mono和Flux都可以发出三种数据信号:元素值,错误信号,完成信号;错误信号,完成信号都是终止信号,终止信号告诉订阅者数据流结束了,错误信号终止数据流同时把错误信息传递给订阅者。
三种信号的特点:
- 错误信号和完成信号都是终止信号,不能共存
- 如果没有发送任何的元素值,而是只是发送错误或者完成信号,表示空数据流
- 如果没有错误信号,没有完成信号,表示一个无限信号流
调用just方法或者其他的方法只是声明数据流,数据流并没有发出,只有进行订阅之后才会触发数据流,不订阅什么都不会发生
Flux.just(1,2,34).subscribe(System.out::print);
Mono.just(1).subscribe(System.out::print);
map:把每一个元素映射成一个新的元素
flatMap:把每个元素转换成一个流,然后再合并成一个大的流
3、Webflux执行流程和核心api
SpringWebflux基于Reactor,默认容器时Netty,Netty是一个高性能的NIO框架,异步非阻塞的框架。
1.SpringWebflux核心控制器DispatchHandler,实现WebHandler
public Mono<Void> handle(ServerWebExchange exchange) {
//加载http的请求头信息
return this.handlerMappings == null ? this.createNotFoundError() : Flux.fromIterable(this.handlerMappings).concatMap((mapping) -> {
//根据请求找到对应的mapping
return mapping.getHandler(exchange);
}).next().switchIfEmpty(this.createNotFoundError()).flatMap((handler) -> {
//调用对应的业务方法
return this.invokeHandler(exchange, handler);
}).flatMap((result) -> {
//处理请求结果
return this.handleResult(exchange, result);
});
}
2.SpringWebflux里面DispatcherHandler,负责请求的处理
HandlerMapping:请求查询到处理的方法
HandlerAdapter:真正负责请求处理
HandlerResulerHandler:响应结果处理
3.SpringWebflux实现函数式编程,两个接口:RouterFunction(路由处理)和HandlerFunction(处理具体方法)
4、SpringWebflux(基于注解编程)
注解编程模式方式和之前SpringMVC使用相似,只需要把参数的值改成Mono或者Flux处理,在springboot中会自动处理webflux请求
public interface TeacherService {
Mono<Teacher> getTeacherById(int id);
Flux<Teacher> listTeacher();
Mono<Void> saveTeacher(Mono<Teacher> teacherMono);
}
@Service
public class TeacherServiceImpl implements TeacherService {
private final Map<Integer,Teacher> teachers = new HashMap<>();
public TeacherServiceImpl(){
teachers.put(1,new Teacher("jack","男",10));
teachers.put(2,new Teacher("marry","女",20));
teachers.put(3,new Teacher("halj","男",18));
teachers.put(4,new Teacher("wuli","男",19));
}
@Override
public Mono<Teacher> getTeacherById(int id) {
return Mono.justOrEmpty(this.teachers.get(id));
}
@Override
public Flux<Teacher> listTeacher() {
return Flux.fromIterable(this.teachers.values());
}
@Override
public Mono<Void> saveTeacher(Mono<Teacher> teacherMono) {
return teacherMono.doOnNext(teacher -> {
int id = this.teachers.size() + 1;
teachers.put(id,teacher);
}).thenEmpty(Mono.empty());
}
}
@RestController
public class TeacherController {
@Autowired
private TeacherService teacherService;
@GetMapping("/teacher/{id}")
public Mono<Teacher> getTeacher(@PathVariable int id){
return teacherService.getTeacherById(id);
}
@GetMapping("/teacher")
public Flux<Teacher> listTeachers(){
return teacherService.listTeacher();
}
@PostMapping("/save")
public Mono<Void> save(@RequestBody Teacher teacher){
Mono<Teacher> just = Mono.just(teacher);
return teacherService.saveTeacher(just);
}
}
SpringMVC与SpringWebFlux底层处理方式:
SpringMVC方式实现,同步阻塞的方式,基于SpringMVC+Servlet+Tomcat
SpringWebFlux方式实现:异步非阻塞方式,基于SpringWebFlux+Reactor+Netty
5、SpringWebflux(基于函数式编程)
1.在使用函数式编程模型操作时候,需要自己初始化服务器
2.基于函数式编程模型时候,有两个核心接口:RouterFunction(实现路由功能,请求转发给对应的Handler)和HandlerFunction(处理请求响应的函数)。核心任务定义两个函数式接口的事项并且启动需要的服务器
3.SpringWebflux请求和响应不在式ServletRequest和ServletResponse,而是ServerRequest和ServerResponse
demo
service层的代码上上面是一样的,
下面是需要自己编程
1、创建handler
public class TeacherHandler {
private final TeacherService teacherService;
public TeacherHandler(TeacherService teacherService) {
this.teacherService = teacherService;
}
//根究id查询
public Mono<ServerResponse> getTeacherById(ServerRequest request){
int id = Integer.valueOf(request.pathVariable("id"));
Mono<Teacher> teacher = this.teacherService.getTeacherById(id);
//把teacher进行转换返回
//使用Reactor操作符flatMap
return teacher.flatMap(teacher1 -> ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(teacher1,
Teacher.class));
}
public Mono<ServerResponse> listTeachers(ServerRequest request){
Flux<Teacher> teacherFlux = this.teacherService.listTeacher();
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(teacherFlux,Teacher.class);
}
public Mono<ServerResponse> save(ServerRequest request){
Mono<Teacher> teacherMono = request.bodyToMono(Teacher.class);
return ServerResponse.ok().build(this.teacherService.saveTeacher(teacherMono));
}
}
/*
*创建netty服务
*/
public class Server {
public static void main(String[] args) throws IOException {
Server server = new Server();
server.createReactorServer();
System.out.println("enter to exit");
}
//创建路由
public RouterFunction<ServerResponse> routingFunction(){
TeacherService teacherService = new TeacherServiceImpl();
//创建handler对象
TeacherHandler teacherHandler = new TeacherHandler(teacherService);
//设置路由
return RouterFunctions.route(GET("/teacher/{id}").and(accept(MediaType.APPLICATION_JSON)),
teacherHandler::getTeacherById).andRoute(GET("/listTeachers").and(accept(MediaType.APPLICATION_JSON)),
teacherHandler::listTeachers);
}
//创建服务器完成适配
public void createReactorServer(){
//路由和handler适配
RouterFunction<ServerResponse> serverResponseRouterFunction = routingFunction();
HttpHandler httpHandler = toHttpHandler(serverResponseRouterFunction);
ReactorHttpHandlerAdapter reactorHttpHandlerAdapter = new ReactorHttpHandlerAdapter(httpHandler);
//创建服务器
HttpServer httpServer = HttpServer.create();
httpServer.handle(reactorHttpHandlerAdapter).bind();
}
}
//webClient测试
public class Client {
public static void main(String[] args) {
//调用服务器地址
WebClient webClient = WebClient.create("http://127.0.0.1:1234");
//根据id查询
String id ="1";
Teacher teacher = webClient.get().uri("/teacher/{id}", id).accept(MediaType.APPLICATION_JSON)
.retrieve().bodyToMono(Teacher.class).block();
System.out.println(teacher.getName());
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步