当前位置: 首页 > 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;可以指定初始容量或…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

python报错No module named ‘tensorflow.keras‘

是由于不同版本的tensorflow下的keras所在的路径不同&#xff0c;结合所安装的tensorflow的目录结构修改from语句即可。 原语句&#xff1a; from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后&#xff1a; from tensorflow.python.keras.lay…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

Linux离线(zip方式)安装docker

目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1&#xff1a;修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本&#xff1a;CentOS 7 64位 内核版本&#xff1a;3.10.0 相关命令&#xff1a; uname -rcat /etc/os-rele…...

回溯算法学习

一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

mac 安装homebrew (nvm 及git)

mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安装 Git&#xff08;推荐&#xff09; 步骤如下&#xff1a;打开终端&#xff08;Terminal.app&#xff09; 1.安装 Homebrew…...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...