当前位置: 首页 > news >正文

Spring Webflux DispatcherHandler源码整理

DispatcherHandler的构造(以RequestMappingHandlerMapping为例)
  1. WebFluxAutoConfiguration中EnableWebFluxConfiguration继承WebFluxConfigurationSupport
    @Bean
    public DispatcherHandler webHandler() {return new DispatcherHandler();
    }
    
  2. DispatcherHandler#setApplicationContext => initStrategies(applicationContext)
    protected void initStrategies(ApplicationContext context) {Map<String, HandlerMapping> mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);ArrayList<HandlerMapping> mappings = new ArrayList<>(mappingBeans.values());AnnotationAwareOrderComparator.sort(mappings);this.handlerMappings = Collections.unmodifiableList(mappings);//Map<String, HandlerAdapter> adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);//this.handlerAdapters = new ArrayList<>(adapterBeans.values());AnnotationAwareOrderComparator.sort(this.handlerAdapters);//Map<String, HandlerResultHandler> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerResultHandler.class, true, false);this.resultHandlers = new ArrayList<>(beans.values());AnnotationAwareOrderComparator.sort(this.resultHandlers);
    }
    
  3. RequestMappingHandlerMapping-> afterPropertiesSet -> AbstractHandlerMethodMapping.initHandlerMethods
    protected void initHandlerMethods() {String[] beanNames = obtainApplicationContext().getBeanNamesForType(Object.class);for (String beanName : beanNames) {if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {Class<?> beanType = obtainApplicationContext().getType(beanName);// 当类被Controller或则RequestMapping标注时查找HandlerMethodif (beanType != null && isHandler(beanType)) {detectHandlerMethods(beanName);}}}}
    
  4. AbstractHandlerMethodMapping#detectHandlerMethods(beanName)
     protected void detectHandlerMethods(final Object handler) {Class<?> handlerType = (handler instanceof String ?obtainApplicationContext().getType((String) handler) : handler.getClass());if (handlerType != null) {final Class<?> userType = ClassUtils.getUserClass(handlerType);Map<Method, T> methods = MethodIntrospector.selectMethods(userType,(MethodIntrospector.MetadataLookup<T>) method -> getMappingForMethod(method, userType));methods.forEach((method, mapping) -> {Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);// invocableMethod保存到MappingRegistry注册表中registerHandlerMethod(handler, invocableMethod, mapping);});}}
    
  5. RequestMappingHandlerMapping#getMappingForMethod(method, handlerType)
    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {RequestMappingInfo info = createRequestMappingInfo(method);if (info != null) {RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);if (typeInfo != null) {info = typeInfo.combine(info);}for (Map.Entry<String, Predicate<Class<?>>> entry : this.pathPrefixes.entrySet()) {if (entry.getValue().test(handlerType)) {String prefix = entry.getKey();if (this.embeddedValueResolver != null) {prefix = this.embeddedValueResolver.resolveStringValue(prefix);}info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);break;}}}return info;
    }
    
  6. RequestMappingHandlerMapping#createRequestMappingInfo(method)
    private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);RequestCondition<?> condition = (element instanceof Class ?getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
    }
    protected RequestMappingInfo createRequestMappingInfo(RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {RequestMappingInfo.Builder builder = RequestMappingInfo.paths(resolveEmbeddedValuesInPatterns(requestMapping.path())).methods(requestMapping.method()).params(requestMapping.params()).headers(requestMapping.headers()).consumes(requestMapping.consumes()).produces(requestMapping.produces()).mappingName(requestMapping.name());if (customCondition != null) {builder.customCondition(customCondition);}return builder.options(this.config).build();}
    
DispatcherHandler的执行(以RequestMappingHandlerMapping为例)
查找handler
  1. DispatcherHandler#handle(exchange)
    public Mono<Void> handle(ServerWebExchange exchange) {if (CorsUtils.isPreFlightRequest(exchange.getRequest())) {return handlePreFlight(exchange);}return Flux.fromIterable(this.handlerMappings).concatMap(mapping -> mapping.getHandler(exchange)).next().switchIfEmpty(createNotFoundError()).flatMap(handler -> invokeHandler(exchange, handler)).flatMap(result -> handleResult(exchange, result));
    }
    
  2. AbstractHandlerMapping#getHandler(exchange)
    public Mono<Object> getHandler(ServerWebExchange exchange) {return getHandlerInternal(exchange) ;
    }
    
  3. AbstractHandlerMethodMapping#getHandlerInternal
    public Mono<HandlerMethod> getHandlerInternal(ServerWebExchange exchange) {this.mappingRegistry.acquireReadLock();try {HandlerMethod handlerMethod;try {handlerMethod = lookupHandlerMethod(exchange);}catch (Exception ex) {return Mono.error(ex);}if (handlerMethod != null) {handlerMethod = handlerMethod.createWithResolvedBean();}return Mono.justOrEmpty(handlerMethod);}finally {this.mappingRegistry.releaseReadLock();}
    }
    
  4. AbstractHandlerMethodMapping#lookupHandlerMethod(exchange)
    protected HandlerMethod lookupHandlerMethod(ServerWebExchange exchange) throws Exception {List<Match> matches = new ArrayList<>();List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(exchange);if (directPathMatches != null) {addMatchingMappings(directPathMatches, matches, exchange);}// 省略部分代码if (!matches.isEmpty()) {Comparator<Match> comparator = new MatchComparator(getMappingComparator(exchange));matches.sort(comparator);Match bestMatch = matches.get(0);handleMatch(bestMatch.mapping, bestMatch.getHandlerMethod(), exchange);return bestMatch.getHandlerMethod();}else {return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), exchange);}
    }
    
执行handler
  1. DispatcherHandler#invokeHandler
    private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {for (HandlerAdapter handlerAdapter : this.handlerAdapters) {if (handlerAdapter.supports(handler)) {return handlerAdapter.handle(exchange, handler);}}return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
    }
    
  2. RequestMappingHandlerAdapter#handle(exchange, handler)
    public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {HandlerMethod handlerMethod = (HandlerMethod) handler;InitBinderBindingContext bindingContext = new InitBinderBindingContext(getWebBindingInitializer(), this.methodResolver.getInitBinderMethods(handlerMethod));InvocableHandlerMethod invocableMethod = this.methodResolver.getRequestMappingMethod(handlerMethod);//Function<Throwable, Mono<HandlerResult>> exceptionHandler =ex -> handleException(ex, handlerMethod, bindingContext, exchange);//return this.modelInitializer.initModel(handlerMethod, bindingContext, exchange).then(Mono.defer(() -> invocableMethod.invoke(exchange, bindingContext))).doOnNext(result -> result.setExceptionHandler(exceptionHandler)).doOnNext(result -> bindingContext.saveModel()).onErrorResume(exceptionHandler);
    }
    
  3. InvocableHandlerMethod#invoke
    public Mono<HandlerResult> invoke(ServerWebExchange exchange, BindingContext bindingContext, Object... providedArgs) {return getMethodArgumentValues(exchange, bindingContext, providedArgs).flatMap(args -> {Object value;Method method = getBridgedMethod();if (KotlinDetector.isSuspendingFunction(method)) {value = CoroutinesUtils.invokeSuspendingFunction(method, getBean(), args);}else {value = method.invoke(getBean(), args);}// 省略部分代码HttpStatus status = getResponseStatus();if (status != null) {exchange.getResponse().setStatusCode(status);}MethodParameter returnType = getReturnType();ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(returnType.getParameterType());boolean asyncVoid = isAsyncVoidReturnType(returnType, adapter);if ((value == null || asyncVoid) && isResponseHandled(args, exchange)) {return (asyncVoid ? Mono.from(adapter.toPublisher(value)) : Mono.empty());}HandlerResult result = new HandlerResult(this, value, returnType, bindingContext);return Mono.just(result);});
    }
    
处理返回结果
  1. DispatcherHandler#handleResult
    private Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {return getResultHandler(result).handleResult(exchange, result) ;
    }
    
  2. DispatcherHandler#getResultHandler => ResponseBodyResultHandler
  3. ResponseBodyResultHandler#handleResult(exchange, result)
    public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {Object body = result.getReturnValue();MethodParameter bodyTypeParameter = result.getReturnTypeSource();return writeBody(body, bodyTypeParameter, exchange);
    }
    

相关文章:

Spring Webflux DispatcherHandler源码整理

DispatcherHandler的构造(以RequestMappingHandlerMapping为例) WebFluxAutoConfiguration中EnableWebFluxConfiguration继承WebFluxConfigurationSupportBean public DispatcherHandler webHandler() {return new DispatcherHandler(); }DispatcherHandler#setApplicationCon…...

【Netty】ByteToMessageDecoder源码解析

目录 1.协议说明 2.类的实现 3.Decoder工作流程 4.源码解析 4.1 ByteToMessageDecoder#channelRead 4.2 累加器Cumulator 4.3 解码过程 4.4 Decoder实现举例 5. 如何开发自己的Decoder 1.协议说明 Netty框架是基于Java NIO框架&#xff0c;性能彪悍&#xff0c;支持的协…...

DevEco Studio设置Nodejs提示路径只能包含英文、数字、下划线等

安装DevEco Studio 3.1.1 Release 设置Nodejs路径使用nodejs默认安装路径 &#xff08;C:\Program Files\nodejs&#xff09; 提示只能包含英文、数字、下划线等 , 不想在安装nodejs请往下看 nodejs默认路径报错 修改配置文件 1、退出DevEco Studio 2、打开配置文件 cmd控制台…...

大模型 Decoder 的生成策略

本文将介绍以下内容&#xff1a; IntroductionGreedy Searchbeam searchSamplingTop-K SamplingTop-p (nucleus) sampling总结 一、Introduction 1、简介 近年来&#xff0c;由于在数百万个网页数据上训练的大型基于 Transformer 的语言模型的兴起&#xff0c;开放式语言生…...

队列和栈相互实现

相关题目 225. 用队列实现栈&#xff1a;弹出元素时&#xff0c;将对首的元素出列加到队尾&#xff0c;直到只剩下初始队列时队尾一个元素为止&#xff0c;然后弹出这个元素&#xff0c;即可实现LIFO 232. 用栈实现队列&#xff1a;用两个栈实现队列的功能&#xff0c;出栈时&a…...

Node.js 是如何处理请求的

前言&#xff1a;在服务器软件中&#xff0c;如何处理请求是非常核心的问题。不管是底层架构的设计、IO 模型的选择&#xff0c;还是上层的处理都会影响一个服务器的性能&#xff0c;本文介绍 Node.js 在这方面的内容。 TCP 协议的核心概念 要了解服务器的工作原理首先需要了…...

数据结构与算法之堆: Leetcode 215. 数组中的第K个最大元素 (Typescript版)

数组中的第K个最大元素 https://leetcode.cn/problems/kth-largest-element-in-an-array/ 描述 给定整数数组 nums 和整数 k&#xff0c;请返回数组中第 k 个最大的元素。请注意&#xff0c;你需要找的是数组排序后的第 k 个最大的元素&#xff0c;而不是第 k 个不同的元素。…...

SpringBoot快速入门

搭建SpringBoot工程&#xff0c;定义hello方法&#xff0c;返回“Hello SpringBoot” ②导入springboot工程需要继承的父工程&#xff1b;以及web开发的起步依赖。 ③编写Controller ④引导类就是SpringBoot项目的一个入口。 写注解写main方法调用run方法 快速构建SpringBoo…...

深度学习笔记_4、CNN卷积神经网络+全连接神经网络解决MNIST数据

1、首先&#xff0c;导入所需的库和模块&#xff0c;包括NumPy、PyTorch、MNIST数据集、数据处理工具、模型层、优化器、损失函数、混淆矩阵、绘图工具以及数据处理工具。 import numpy as np import torch from torchvision.datasets import mnist import torchvision.transf…...

高效的开发流程搭建

目录 1. 搭建 AI codebase 环境kaggle的服务器1. 搭建 AI codebase 环境 python 、torch 以及 cuda版本,对AI的影响最大。不同的版本,可能最终计算出的结果会有区别。 硬盘:PCIE转SSD的卡槽,, GPU: 软件源: Anaconda: 一定要放到固态硬盘上。 VS code 的 debug功能…...

浅谈OV SSL 证书的优势

随着网络威胁日益增多&#xff0c;保护网站和用户安全已成为每个企业和组织的重要任务。在众多SSL证书类型中&#xff0c;OV&#xff08;Organization Validation&#xff09;证书以其独特的优势备受关注。让我们深入探究OV证书的优势所在&#xff0c;为网站安全搭建坚实的防线…...

一篇博客学会系列(3) —— 对动态内存管理的深度讲解以及经典笔试题的深度解析

目录 动态内存管理 1、为什么存在动态内存管理 2、动态内存函数的介绍 2.1、malloc和free 2.2、calloc 2.3、realloc 3、常见的动态内存错误 3.1、对NULL指针的解引用操作 3.2、对动态开辟空间的越界访问 3.3、对非动态开辟内存使用free释放 3.4、使用free释放一块动态…...

【C++ techniques】虚化构造函数、虚化非成员函数

constructor的虚化 virtual function&#xff1a;完成“因类型而异”的行为&#xff1b;constructor&#xff1a;明确类型时构造函数&#xff1b;virtual constructor&#xff1a;视其获得的输入&#xff0c;可产生不同的类型对象。 //假如写一个软件&#xff0c;用来处理时事…...

蓝牙核心规范(V5.4)11.6-LE Audio 笔记之初识音频位置和通道分配

专栏汇总网址:蓝牙篇之蓝牙核心规范学习笔记(V5.4)汇总_蓝牙核心规范中文版_心跳包的博客-CSDN博客 爬虫网站无德,任何非CSDN看到的这篇文章都是盗版网站,你也看不全。认准原始网址。!!! 音频位置 在以前的每个蓝牙音频规范中,只有一个蓝牙LE音频源和一个蓝牙LE音频接…...

mysql双主+双从集群连接模式

架构图&#xff1a; 详细内容参考&#xff1a; 结果展示&#xff1a; 178.119.30.14(主) 178.119.30.15(主) 178.119.30.16(从) 178.119.30.17(从)...

嵌入式中如何用C语言操作sqlite3(07)

sqlite3编程接口非常多&#xff0c;对于初学者来说&#xff0c;我们暂时只需要掌握常用的几个函数&#xff0c;其他函数自然就知道如何使用了。 数据库 本篇假设数据库为my.db,有数据表student。 nonamescore4嵌入式开发爱好者89.0 创建表格语句如下&#xff1a; CREATE T…...

RandomForestClassifier 与 GradientBoostingClassifier 的区别

RandomForestClassifier&#xff08;随机森林分类器&#xff09;和GradientBoostingClassifier&#xff08;梯度提升分类器&#xff09;是两种常用的集成学习方法&#xff0c;它们之间的区别分以下几点。 1、基础算法 RandomForestClassifier&#xff1a;随机森林分类器是基于…...

计组——I/O方式

一、程序查询方式 CPU不断轮询检查I/O控制器中“状态寄存器”&#xff0c;检测到状态为“已完成”之后&#xff0c;再从数据寄存器取出输入数据。 过程&#xff1a; 1.CPU执行初始化程序&#xff0c;并预置传送参数&#xff1b;设置计数器、设置数据首地址。 2. 向I/O接口发…...

jsbridge实战2:Swift和h5的jsbridge通信

[[toc]] demo1: 文本通信 h5 -> app 思路&#xff1a; h5 全局属性上挂一个变量app 接收这个变量的内容关键API: navigation代理 navigationAction.request.url?.absoluteString // 这个变量挂载在 request 的 url 上 &#xff0c;在浏览器实际无法运行&#xff0c;因…...

集合原理简记

HashMap 无论在构造函数是否指定数组长度&#xff0c;进行的都是延迟初始化 构造函数作用&#xff1a; 阈值&#xff1a;threshold&#xff0c;每次<<1 &#xff0c;数组长度 负载因子 无参构造&#xff1a;设置默认的负载因子 有参&#xff1a;可以指定初始容量或…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

idea大量爆红问题解决

问题描述 在学习和工作中&#xff0c;idea是程序员不可缺少的一个工具&#xff0c;但是突然在有些时候就会出现大量爆红的问题&#xff0c;发现无法跳转&#xff0c;无论是关机重启或者是替换root都无法解决 就是如上所展示的问题&#xff0c;但是程序依然可以启动。 问题解决…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

CSS设置元素的宽度根据其内容自动调整

width: fit-content 是 CSS 中的一个属性值&#xff0c;用于设置元素的宽度根据其内容自动调整&#xff0c;确保宽度刚好容纳内容而不会超出。 效果对比 默认情况&#xff08;width: auto&#xff09;&#xff1a; 块级元素&#xff08;如 <div>&#xff09;会占满父容器…...