springboot-响应式编程

后端 / 笔记 / 2021-10-17

springboot-响应式编程

认识响应式编程

webflux是 springframework 在5.0 引入的,响应式web框架。与springmvc不同,webflux不需要servletapi,完全异步且无阻塞。

webflux可以在,有限资源情况下,提高系统的吞吐量和伸缩性,意味着 在相同资源情况下,webflux可以处理更多的请求。

比较MVC和WebFlux

MVC

MVC工作方式是,主线程接收到请求request-> 准备数据->返回数据

整个过程是,单线程阻塞的,用户会感觉等待时间很长是因为,在处理好请求后才返回数据给客户端,如果请求数量很多,吞吐量就上不去。

WebFlux

WebFlux工作流程是 主线程收到请求-> 立即返回数据与函数组合-> 开启一个新的线程去做实际的数据准备工作,进行业务操作->完成工作->返回结果

使用WebFlux好处

你来了,我立马应答你,但是服务需要等待,而不是你来了半天没人搭理你,咨询服务半天也回复不了。

如果开发I/O密集型服务,可以采用WebFlux实现

认识Mono和Flux

Mono 和Flux属于事件发布者,为消费者提供订阅接口。当有事件发生时,Mono或Flux会回调消费者的对应方法,然后通知消费者相应的事件。这也是响应式编程模型。

Mono和Flux区别

  • Flux可以发送很多Item,并且这些Item可以经过若干算子然后才被订阅
  • Mono主要用于返回单个数据,Flux用于返回多个数据。
  • 如果返回单个对象则用 Mono如果返回对象集合则用Flux
  • Flux和Mono之间可以相互转换,把多个Mono对象合到一起就是一个Flux对象

Mono消息通知

消息通知(事件发布者)方法(事件订阅者)
正常消息onNext()
序列结束消息onComplete()
错误消息onError()

开发WebFlux流程

注解式开发流程

webflux是响应式框架,其中使用注解式开发方式和SpringMvc一样。

响应式开发流程

  1. 创建Handler类

    Handler类相当于SpringMvc中Controller层中的方法体,在响应式编程中,请求对象不再是HttpServletRequest和HttpServletResponse,而是ServerRequestServerResponse

  2. 配置RouterFunction

    RouterFunction和注解@RequestMapping相似,都用于提供URL路径。

HelloWorld

光说不干假把式,写个HelloWorld看看吧。

导入Maven依赖

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

编写controller

这些写个Mono包装的String返回值

package com.lu.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

@RestController
public class HelloWorldController {
    @GetMapping("/")
    public Mono<String> helloWorld(){
        return Mono.just("Hello,WebFlux!");
    }
}

实现一个RestFul风格的WebFlux接口

创建实体类

package com.lu.entity;

public class UserInfo {
    private String name;
    private Integer age;
    private String addr;

    public UserInfo(String name, Integer age, String addr) {
        this.name = name;
        this.age = age;
        this.addr = addr;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }
}

dao实现

package com.lu.dao;

import java.util.List;

public interface UserDao<T> {
    void insert(T user);
    void delete(T user);
    void update(T user,Integer id);
    T query(String name);
    List<T> getAll();
}




package com.lu.dao;

import com.lu.entity.UserInfo;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.List;

@Repository
public class UserDaoImpl implements UserDao<UserInfo> {
    private static List<UserInfo> list = new ArrayList<>();

    static {
        list.add(new UserInfo("Fang",22,"shanxi"));
        list.add(new UserInfo("Jack",21,"USA"));
    }

    @Override
    public void insert(UserInfo user) {
        list.add(user);
    }

    @Override
    public void delete(UserInfo user) {
        list.remove(user);
    }

    @Override
    public void update(UserInfo user, Integer id) {
        list.set(id,user);
    }

    @Override
    public UserInfo query(String name) {
        for (UserInfo userInfo : list) {
            if (userInfo.getName().equals(name)) return userInfo;
        }
        return null;
    }

    @Override
    public List<UserInfo> getAll() {
        return list;
    }
}

service实现

package com.lu.controller.service;

import java.util.List;

public interface UserService<T> {
    void insertUser(T user);

    void deleteUser(T user);

    void updateUser(Integer id, T user);

    T findUserByName(String name);
    List<T> getAllUser();

    T findUserById(Integer id);
}




package com.lu.controller.service;

import com.lu.dao.UserDao;
import com.lu.entity.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserServiceImpl implements UserService<UserInfo> {
    @Autowired
    private UserDao dao;

    @Override
    public void insertUser(UserInfo user) {
        dao.insert(user);
    }

    @Override
    public void deleteUser(UserInfo user) {

        dao.delete(user);
    }

    @Override
    public void updateUser(Integer id, UserInfo user) {
        dao.update(user, id);
    }

    @Override
    public UserInfo findUserByName(String name) {
        return (UserInfo) dao.query(name);
    }

    @Override
    public List<UserInfo> getAllUser() {
        return dao.getAll();
    }

    @Override
    public UserInfo findUserById(Integer id) {
        List<UserInfo> all = dao.getAll();
        return all.get(id);
    }

}

controller 实现

package com.lu.controller;

import com.lu.controller.service.UserService;
import com.lu.entity.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Optional;

@RestController
@RequestMapping("/api/v1")
public class UserController {
    @Autowired
    private UserService<UserInfo> service;
    // 获取所有用户
    @GetMapping("/getall")
    public Flux<UserInfo> getall(){
        return Flux.fromStream(service.getAllUser().stream());
    }
    // 获取单个用户
    @GetMapping("/get/{id}")
    public Mono<UserInfo> getUserById(@PathVariable Integer id){
        return Mono.just(service.findUserById(id));
    }
    // 创建用户
    @PostMapping("/post")
    public Mono<ResponseEntity<String>> createUser(UserInfo userInfo){
        Optional.of(userInfo).ifPresent(service::insertUser);
        return Mono.just(new ResponseEntity<>("添加成功", HttpStatus.CREATED));
    }
    // 修改用户
    @PutMapping("/put/{id}")
    public Mono<ResponseEntity<String>> modifyUser(@PathVariable("id") Integer id,UserInfo userInfo){
        service.updateUser(id,userInfo);
        return Mono.just(new ResponseEntity<>("修改成功",HttpStatus.CREATED));
    }
    // 删除用户
    @DeleteMapping("/del/{id}")
    public Mono<ResponseEntity<String>> deleteUser(@PathVariable("id") Integer id){
        service.deleteUser(service.findUserById(id));
        return Mono.just(new ResponseEntity<>("删除成功",HttpStatus.CREATED));
    }
}