目录
- 传送门
- 前言
- 一、组件对比
- 二、WebFlux
- 1、引入
- 2、Reactor Core
- 3、DispatcherHandler
- 3.1、请求处理流程
- 4、注解开发
- 4.1、目标方法传参
- 4.2、返回值写法
- 5、文件上传
- 6、错误处理
- 7、RequestContext
- 8、自定义Flux配置
- 9、Filter
传送门
SpringMVC的源码解析(精品)
Spring6的源码解析(精品)
SpringBoot3框架(精品)
MyBatis框架(精品)
MyBatis-Plus
SpringDataJPA
SpringCloudNetflix
SpringCloudAlibaba(精品)
Shiro
SpringSecurity
java的LOG日志框架
Activiti(敬请期待)
JDK8新特性
JDK9新特性
JDK10新特性
JDK11新特性
JDK12新特性
JDK13新特性
JDK14新特性
JDK15新特性
JDK16新特性
JDK17新特性
JDK18新特性
JDK19新特性
JDK20新特性
JDK21新特性
其他技术文章传送门入口
前言
由于面试问到的比较多,而且做java开发这块还是需要真正掌握的。
现有笔记尚硅谷雷锋阳老师的:SpringBoot3全栈指南,是我目前见过的最好笔记了。
参考视频尚硅谷雷锋阳老师的:SpringBoot零基础教程,面试&加薪必会,视频是24小时31分钟的高质量教程。
参考代码:https://gitee.com/leifengyang/spring-boot-3
最经典的20个Spring Boot面试题,95%以上会被问到,不服来战
为了防止雷锋阳老师的日志查看不到,这里分类整理一下。下面文章不定时更新
SpringBoot3核心特性-快速入门
SpringBoot3核心特性-Web开发
SpringBoot3核心特性-数据访问
SpringBoot3核心特性-基础特性
SpringBoot3核心特性-核心原理
SpringBoot3场景整合
SpringBoot3响应式编程全套-Reactor核心
SpringBoot3响应式编程全套-Spring Webflux
SpringBoot3响应式编程全套-R2DBC
SpringBoot3响应式编程全套-Spring Security Reactive
一、组件对比
Mono: 返回0|1 数据流
Flux:返回N数据流
二、WebFlux
底层基于Netty实现的Web容器与请求/响应处理机制
参照:https://docs.spring.io/spring-framework/reference/6.0/web/webflux.html
1、引入
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.1.6</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency></dependencies>
Context 响应式上下文数据传递; 由下游传播给上游;
以前: 浏览器 --> Controller --> Service --> Dao: 阻塞式编程
现在: Dao(数据源查询对象【数据发布者】) --> Service --> Controller --> 浏览器: 响应式
大数据流程: 从一个数据源拿到大量数据进行分析计算;
ProductVistorDao.loadData().distinct().map().filter().handle()
.subscribe();
;//加载最新的商品浏览数据
2、Reactor Core
HttpHandler、HttpServer
public static void main(String[] args) throws IOException {//快速自己编写一个能处理请求的服务器//1、创建一个能处理Http请求的处理器。 参数:请求、响应; 返回值:Mono<Void>:代表处理完成的信号HttpHandler handler = (ServerHttpRequest request,ServerHttpResponse response)->{URI uri = request.getURI();System.out.println(Thread.currentThread()+"请求进来:"+uri);//编写请求处理的业务,给浏览器写一个内容 URL + "Hello~!"
// response.getHeaders(); //获取响应头
// response.getCookies(); //获取Cookie
// response.getStatusCode(); //获取响应状态码;
// response.bufferFactory(); //buffer工厂
// response.writeWith() //把xxx写出去
// response.setComplete(); //响应结束//数据的发布者:Mono<DataBuffer>、Flux<DataBuffer>//创建 响应数据的 DataBufferDataBufferFactory factory = response.bufferFactory();//数据BufferDataBuffer buffer = factory.wrap(new String(uri.toString() + " ==> Hello!").getBytes());// 需要一个 DataBuffer 的发布者return response.writeWith(Mono.just(buffer));};//2、启动一个服务器,监听8080端口,接受数据,拿到数据交给 HttpHandler 进行请求处理ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(handler);//3、启动Netty服务器HttpServer.create().host("localhost").port(8080).handle(adapter) //用指定的处理器处理请求.bindNow(); //现在就绑定System.out.println("服务器启动完成....监听8080,接受请求");System.in.read();System.out.println("服务器停止....");}
3、DispatcherHandler
SpringMVC: DispatcherServlet;
SpringWebFlux: DispatcherHandler
3.1、请求处理流程
● HandlerMapping:请求映射处理器; 保存每个请求由哪个方法进行处理
● HandlerAdapter:处理器适配器;反射执行目标方法
● HandlerResultHandler:处理器结果处理器;
SpringMVC: DispatcherServlet 有一个 doDispatch() 方法,来处理所有请求;
WebFlux: DispatcherHandler 有一个 handle() 方法,来处理所有请求;
public Mono<Void> handle(ServerWebExchange exchange) { if (this.handlerMappings == null) {return createNotFoundError();}if (CorsUtils.isPreFlightRequest(exchange.getRequest())) {return handlePreFlight(exchange);}return Flux.fromIterable(this.handlerMappings) //拿到所有的 handlerMappings.concatMap(mapping -> mapping.getHandler(exchange)) //找每一个mapping看谁能处理请求.next() //直接触发获取元素; 拿到流的第一个元素; 找到第一个能处理这个请求的handlerAdapter.switchIfEmpty(createNotFoundError()) //如果没拿到这个元素,则响应404错误;.onErrorResume(ex -> handleDispatchError(exchange, ex)) //异常处理,一旦前面发生异常,调用处理异常.flatMap(handler -> handleRequestWith(exchange, handler)); //调用方法处理请求,得到响应结果}
● 1、请求和响应都封装在 ServerWebExchange 对象中,由handle方法进行处理
● 2、如果没有任何的请求映射器; 直接返回一个: 创建一个未找到的错误; 404; 返回Mono.error;终结流
● 3、跨域工具,是否跨域请求,跨域请求检查是否复杂跨域,需要预检请求;
● 4、Flux流式操作,先找到HandlerMapping,再获取handlerAdapter,再用Adapter处理请求,期间的错误由onErrorResume触发回调进行处理;
源码中的核心两个:
● handleRequestWith: 编写了handlerAdapter怎么处理请求
● handleResult: String、User、ServerSendEvent、Mono、Flux …
concatMap: 先挨个元素变,然后把变的结果按照之前元素的顺序拼接成一个完整流
private <R> Mono<R> createNotFoundError() {Exception ex = new ResponseStatusException(HttpStatus.NOT_FOUND);return Mono.error(ex);}
Mono.defer(() -> {Exception ex = new ResponseStatusException(HttpStatus.NOT_FOUND);return Mono.error(ex);}); //有订阅者,且流被激活后就动态调用这个方法; 延迟加载;
4、注解开发
4.1、目标方法传参
https://docs.spring.io/spring-framework/reference/6.0/web/webflux/controller/ann-methods/arguments.html
4.2、返回值写法
sse和websocket区别:
● SSE:单工;请求过去以后,等待服务端源源不断的数据
● websocket:双工: 连接建立后,可以任何交互;
5、文件上传
https://docs.spring.io/spring-framework/reference/6.0/web/webflux/controller/ann-methods/multipart-forms.html
class MyForm {private String name;private MultipartFile file;// ...}@Controller
public class FileUploadController {@PostMapping("/form")public String handleFormUpload(MyForm form, BindingResult errors) {// ...}}
现在
@PostMapping("/")
public String handle(@RequestPart("meta-data") Part metadata, @RequestPart("file-data") FilePart file) { // ...
}
6、错误处理
@ExceptionHandler(ArithmeticException.class)public String error(ArithmeticException exception){System.out.println("发生了数学运算异常"+exception);//返回这些进行错误处理;
// ProblemDetail: 建造者:声明式编程、链式调用
// ErrorResponse : return "炸了,哈哈...";}
7、RequestContext
8、自定义Flux配置
WebFluxConfigurer
容器中注入这个类型的组件,重写底层逻辑
@Configuration
public class MyWebConfiguration {//配置底层@Beanpublic WebFluxConfigurer webFluxConfigurer(){return new WebFluxConfigurer() {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedHeaders("*").allowedMethods("*").allowedOrigins("localhost");}};}
}
9、Filter
@Component
public class MyWebFilter implements WebFilter {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();System.out.println("请求处理放行到目标方法之前...");Mono<Void> filter = chain.filter(exchange); //放行//流一旦经过某个操作就会变成新流Mono<Void> voidMono = filter.doOnError(err -> {System.out.println("目标方法异常以后...");}) // 目标方法发生异常后做事.doFinally(signalType -> {System.out.println("目标方法执行以后...");});// 目标方法执行之后//上面执行不花时间。return voidMono; //看清楚返回的是谁!!!}
}