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一样。
响应式开发流程
-
创建Handler类
Handler类相当于SpringMvc中Controller层中的方法体,在响应式编程中,请求对象不再是HttpServletRequest和HttpServletResponse,而是
ServerRequest
和ServerResponse
-
配置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));
}
}