WebFlux

响应式web与阻塞式web组件对应关系

优点:
底层完全基于netty+reactor+springweb
完成的一个全异步,非阻塞的web响应式框架
底层:异步+消息队列(内存) +事件回调机制 = 整个系统
使用少量资源处理大量请求
组件对比:
WebFlux_第1张图片
Mono:返回0/1数据流
Flux:返回n数据流

引入&介绍

底层基于netty实现的web容器与请求/响应处理机制
引入依赖pom.xml
父依赖

    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>3.1.6version>
    parent>

子模块:webflux

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webfluxartifactId>
        dependency>

响应式流程:
背压模式
dao(数据源查询对象:数据包发布者)
–>service–>controller–>浏览器
Context响应式上下文数据传递:由下游传递给上游
大数据流程:从一个数据源拿到大量数据进行分析计算
ProductorVistorDao.loadData()
.distinct()
.map()
.filter()
.handler()

.subscribe();//加载最新的商品浏览数据

入门案例,使用原生api自己搭建服务器

使用HttpHanlder,HttpServlet原生Reactor-Netty api
编写一个服务器

    public static void main(String[] args) throws Exception{
        //快速自己编写一个能处理请求的服务器

        //1.创建一个能处理http请求的处理器
        //参数:请求和响应
        //返回值Mono:代表处理完成的信号
        HttpHandler handler = (ServerHttpRequest req, ServerHttpResponse resp) -> {
            //编写请求处理业务
            System.out.println("request entry,uri:" + req.getURI());
            //响应给浏览器内容
            //数据发布者:Mono,just
            //创建响应数据的dataBuffer
            DataBufferFactory dataBufferFactory = resp.bufferFactory();
            DataBuffer dataBuffer = dataBufferFactory.wrap(String.valueOf(req.getURI()).getBytes());
            //需要一个dataBuffer的发布者
            return resp.writeWith(Mono.just(dataBuffer));
        };

        //2.启动一个服务器,监听8080端口,接收数据,拿到数据,交给handler,进行请求
        ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(handler);
        HttpServer.create()
                .host("localhost")
                .port(8080)
                .handle(adapter)//用指定的处理器处理请求
                .bindNow();
        System.out.println("server run success");
        System.in.read();
    }

DispatcherHandler

springMvc: dispatcherServlet
springWebFlux:DispatcherHandler

1.请求处理流程

返回单个数据

    @GetMapping("/start")
    public Mono<String> returnStr() {
        return Mono.just("req success");
    }

返回一组数据

    @GetMapping("/reqFlux")
    public Flux<String> reqFlux () {
        return Flux.just("req success1","req success2","req success3");
    }

配合Flux完成SSE:server send event(服务端事件推送)
chatGPT在用

    @GetMapping(value = "/reqSse",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> reqSse () {
        return Flux.range(1,10)
                .map(item -> "req" + item)
                .delayElements(Duration.ofMillis(500));
    }

SSE的完整api

    @GetMapping("/sseApi")
    public Flux<ServerSentEvent<String>>sseApi() {
        return Flux.range(1,10)
                .map(item -> {
                    return ServerSentEvent.builder("sse:" + item)
                            .id(item + "")
                            .comment("comment")
                            .event("event")
                            .build();
                })
                .delayElements(Duration.ofMillis(500));
    }

DispathcerHandler源码

1.请求处理流程

handlerMappings:
请求映射处理器,保存每个请求有哪个方法进行处理
handlerAdapter:
处理器适配器,反射执行目标方法
handlerResultHandler:
处理器结果处理器
SpringMVC:DispatcherServlet有一个doDispatch()方法处理所有请求
WebFlux:DispatcherHandler有一个handle()方法处理所有请求

	@Override
	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()//直接触发获取元素,拿到流的第一个元素,找到第一个能处理请求的handlerApapter
				.switchIfEmpty(createNotFoundError())//如果没拿到这个元素,响应404错误
				.onErrorResume(ex -> handleDispatchError(exchange, ex))//异常处理,一旦前面发生异常,调用handleDispatchError()处理
				.flatMap(handler -> handleRequestWith(exchange, handler));//调用方法处理请求,得到结果
	}

流程:
1.请求和响应都封装在ServerWebExchange对象中,由handle方法进行处理
2.如果没有任何请求映射器,直接返回一个:创建一个未犯过错误(404)

    private <R> Mono<R> createNotFoundError() {
        return Mono.defer(() -> {
            Exception ex = new ResponseStatusException(HttpStatus.NOT_FOUND);
            return Mono.error(ex);
        });//有订阅者且流被激活后动态调用这个方法,延迟加载
    }

3.跨域工具检查请求是否是跨域请求
跨域请求检查是否复杂跨域,需要预检请求
4.Flux流式操作:先找到HandlerMapping,再获取handlerApapter,再用adapter处理请求
期间错误由onErrorResume触发回调进行处理
contactMap():先挨个元素变,然后把变的结果按照之前元素的顺序拼接成一个完整的流
核心:
handleRequestWith():编写了handlerAdapter怎么处理请求
handleResult():

filter等其他api

全局异常处理(同之前)
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler(ArithmeticException.class)
    public String error(ArithmeticException exception) {
      log.error("exception happen:" + exception.getMessage(),exception);
      return "server error: " + exception.getMessage();
    }
}
目标方法传参
controller方法参数 描述
ServerWebExchange 封装了请求和响应对象的对象
@PathVariable 路径变量
@RequestParam 请求参数
@RequestHeader 请求头
@RequestPart 获取文件上传数据 multipart/form-data
webFlux config

@EnableWebFlux:开启webFlux自定义
不建议使用,会禁用webFlux默认效果,完全自定义
WebFluxAutoConfiguration的自动配置会默认生效
自定义Flux配置
webFluxConfigurer
容器中注入这个类型的组件,重写底层逻辑
自定义配置

@Configuration
public class WebFluxConfig {

    //配置底层
    @Bean
    public WebFluxConfigurer webFluxConfigurer() {
        return new WebFluxConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedHeaders("*")
                        .allowedMethods("*")
                        .allowedOrigins("*");
            }
        };
    }
}
filter

自定义过滤器
流一旦经过某些操作之后,会编程新流

public class MyWebFilter implements WebFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        //放行
        Mono<Void> filter = chain.filter(exchange);
        
        //流一旦经过某个操作就会变成新流
        return filter.doFinally(singleType -> {
                    //目标方法执行之后,要做的事情
                })
                .doOnError(err -> {
                    //目标方法发生异常之后做的事情
                });
        //看清返回的是哪个流
    }
}

你可能感兴趣的:(spring,boot)