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());
   }
}
posted @   张and强  阅读(395)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示