【响应式编程/笔记】Webflux

部署运行你感兴趣的模型镜像

Webflux

概要:底层完全基于netty+reactor+springweb 完成一个全异步非阻塞的web响应式框架。异步+消息队列(内存)+事件回调机制 = 整套系统,能使用少量资源处理大量请求。

  • 依赖引入
	<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.5.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <dependency>
        <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-webflux</artifactId>
      </dependency>

原生API写法启动Webflux(Reactive Core)

public class SpringWebfluxProjectApplication {

    public static void main(String[] args) throws IOException {
        // 创建一个能处理Http请求的处理器。参数:请求、响应、返回值。
        HttpHandler httpHandler = (ServerHttpRequest request, ServerHttpResponse response)->{
            System.out.println("请求进来了"+request.getURI());
            System.out.println("当前线程"+Thread.currentThread());
            // 编写请求处理的业务,给浏览器写一个内容
            response.getHeaders(); // 获取响应头
            response.getCookies(); // 获取cookies
            response.getStatusCode(); // 获取响应状态码
//            response.bufferFactory(); // buffer工厂
            DataBufferFactory factory = response.bufferFactory();
            DataBuffer buffer = factory.wrap( new String(request.getURI().toString()).getBytes());
//            response.setComplete();// 响应结束
            return response.writeWith(Mono.just(buffer)); // 把数据写出去到网页
        };
        //启动一个服务器,监听8080端口,接收数据,拿到数据交给HttpHandler处理
        ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);
        // 启动Netty服务器
        HttpServer.create()
                .host("localhost")
                .port(8080)
                .handle(adapter)
                .bindNow();
        System.out.println("服务器启动完成...监听8080端口");
        System.in.read();
        System.out.println("服务器结束");
    }

}

使用Spring的方式启动

  • 自己要pom依赖拉入的是webflux依赖,那么他就是用netty启动。他和spring-boot-starter-web冲突的。两个选一个,他也向下兼容,springMvc部分写法还是一样。
@SpringBootApplication
public class SpringWebfluxApplication {

    public static void main(String[] args) throws IOException {
        SpringApplication.run(SpringWebfluxApplication.class,args);
    }

}
@RestController
public class HelloController {

    // WebFlux; 向下兼容原来SpringMvc的大多数注解和API
    @GetMapping("/hello")
    public String hello(){
        return "hello world !";
    }
    // 推荐
    // 返回单个对象就用Mono
    // 返回多个数据就用Flux
    @GetMapping("/haha")
    public Mono<String> haha(){
        return Mono.just("哈哈");
    }
    @GetMapping("/hehe")
    public Flux<String> hehe(){
        return Flux.just("呵呵","呵呵呵");
    }
    // 配合Flux,完成 SSE, Server Send Event 服务端事件推送
    // SSE测试: chatgpt再用,服务端推送
    @GetMapping(value = "/sse",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux sse(){
        return Flux.range(0,10)
                .map(i->"ha-"+i)
                .delayElements(Duration.ofMillis(500));
    }
}

DispatcherHandler

  • SpringMvc:使用的是DispatcherServlet中的DoDispatch()方法处理所有请求。
  • SpringWebflux:使用是DispatcherHandler中的handle()方法处理请求。
	// 处理器映射器 每个请求由哪个方法处理
    @Nullable
    private List<HandlerMapping> handlerMappings;
    // 处理器适配器 反射执行目标方法
    @Nullable
    private List<HandlerAdapter> handlerAdapters;
    // 处理器结果处理器
    @Nullable
    private List<HandlerResultHandler> resultHandlers;
  • Handle()方法
  public Mono<Void> handle(ServerWebExchange exchange) {
  		// 如果没有找到对应的请求映射器,返回一个404 Mono.error
        if (this.handlerMappings == null) {
            return this.createNotFoundError();
        } else {
        	// CorsUtils检查是否跨域请求
            return CorsUtils.isPreFlightRequest(exchange.getRequest()) ? this.handlePreFlight(exchange) : 
            // concatMap遍历获取能处理该请求的mapping
            // next拿到流的第一个元素,即如果以后多个handler能处理该请求,则拿第一个handlerAdapter
            // switchIfEmpty 如果每日以后拿到元素。则返回404
            // onErrorResume 异常处理
            // flatMap 如果有元素,则直接调用方法处理请求
            Flux.fromIterable(this.handlerMappings).concatMap((mapping) -> {
                return mapping.getHandler(exchange);
            }).next().switchIfEmpty(this.createNotFoundError()).onErrorResume((ex) -> {
                return this.handleResultMono(exchange, Mono.error(ex));
            }).flatMap((handler) -> {
                return this.handleRequestWith(exchange, handler);
            });
        }
    }

  private <R> Mono<R> createNotFoundError() {
  		//defer 有订阅者,且流被激活以后,就动态调用该方法
        return Mono.defer(() -> {
            Exception ex = new ResponseStatusException(HttpStatus.NOT_FOUND);
            return Mono.error(ex);
        });
    }
  • HandlerRequestWith【编写HandlerAdapter怎么处理请求】\
  private Mono<Void> handleRequestWith(ServerWebExchange exchange, Object handler) {
        if (ObjectUtils.nullSafeEquals(exchange.getResponse().getStatusCode(), HttpStatus.FORBIDDEN)) {
            return Mono.empty();
        } else {
            if (this.handlerAdapters != null) {
                Iterator var3 = this.handlerAdapters.iterator();

                while(var3.hasNext()) {
                    HandlerAdapter adapter = (HandlerAdapter)var3.next();
                    if (adapter.supports(handler)) {
                        Mono<HandlerResult> resultMono = adapter.handle(exchange, handler);
                        return this.handleResultMono(exchange, resultMono);
                    }
                }
            }

            return Mono.error(new IllegalStateException("No HandlerAdapter: " + String.valueOf(handler)));
        }
    }
  • HandlerResult【处理返回结果】
    private Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult handlerResult, String description) {
        if (this.resultHandlers != null) {
            Iterator var4 = this.resultHandlers.iterator();

            while(var4.hasNext()) {
                HandlerResultHandler resultHandler = (HandlerResultHandler)var4.next();
                if (resultHandler.supports(handlerResult)) {
                    description = description + " [DispatcherHandler]";
                    return resultHandler.handleResult(exchange, handlerResult).checkpoint(description);
                }
            }
        }

        return Mono.error(new IllegalStateException("No HandlerResultHandler for " + String.valueOf(handlerResult.getReturnValue())));
    }

目标方法传参

// ServerWebExchange 封装了请求和响应对象。 自定义获取request和Response
    // WebSession 直接写到方法里可以获取session
    // HttpMethod 是获取请求方式
    // @PathVariable 获取路径变量
    // MatrixVariable 获取矩阵变量
    // @RequestParam 获取请求参数
    // @RequestHeader 获取请求头内参数的
    // @CookieValue 获取Cookie的value的
    // @RequestBody 获取请求体的
    // HttpEntity 获取请求头和请求体,他是header和body的封装
    // @RequestPart 获取文件上传的数据 multipart/form-data
    // @ModelAttribute 将请求体封装到对象上
    @GetMapping("/getWebExchange")
    public String webExchange(ServerWebExchange exchange,
                              WebSession webSession,
                              HttpMethod method,
                              @PathVariable(value = "id") Integer id,
                              @RequestParam HashMap<String,Integer> params,
                              @RequestHeader(value = "Contnet-Type",required = false) String header,
                              @CookieValue(value = "userInfo",required = false) String cookie,
                              @RequestBody Object objectBody,
                              HttpEntity<String> httpEntity,
                              @RequestPart MultipartFile file,
                              @ModelAttribute Object object,

                              ){
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        Object data = webSession.getAttribute("data");

        String methodName = method.name();

        httpEntity.getHeaders();
        httpEntity.getBody();
        
        return null;
    }

自定义flux配置

@Configuration
public class webFluxConfig {
    // 配置底层 类似于 WebMvcConfig
    @Bean
    public WebFluxConfigurer webFluxConfigurer(){
        return new WebFluxConfigurer(){
            // 配置跨域
            @Override
            public void addCorsMappings(CorsRegistry registry) {
               registry.addMapping("/**")
                       .allowedHeaders("*")
                       .allowedMethods("*")
                       .allowedOrigins("*");
            }
        };
    }
}

Filter用法


@Component
public class MyWebFilter implements WebFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        System.out.println("请求处理放行目标之前");
        Mono<Void> filter = chain
                .filter(exchange) //放行
                ;

        // 如果操作老流,那么就得返回一个新的变量,不能直接返回filter得返回newFiler。新的操作才会追加
        Mono<Void>  newFilter = filter
                .doOnError(err->{
                    System.out.println("发生异常后处理数据");
                })
                .doFinally(signalType -> {
                    System.out.println("目标方法执行之后触发");
                });

        return newFilter;
    }
}

您可能感兴趣的与本文相关的镜像

FLUX.1-dev

FLUX.1-dev

图片生成
FLUX

FLUX.1-dev 是一个由 Black Forest Labs 创立的开源 AI 图像生成模型版本,它以其高质量和类似照片的真实感而闻名,并且比其他模型更有效率

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AloneLie

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值