Spring Webflux DispatcherHandler源码整理
DispatcherHandler的构造(以RequestMappingHandlerMapping为例)
- WebFluxAutoConfiguration中EnableWebFluxConfiguration继承WebFluxConfigurationSupport
@Bean public DispatcherHandler webHandler() {return new DispatcherHandler(); } - 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); } - 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);}}}} - 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);});}} - 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; } - 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
- 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)); } - AbstractHandlerMapping#getHandler(exchange)
public Mono<Object> getHandler(ServerWebExchange exchange) {return getHandlerInternal(exchange) ; } - 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();} } - 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
- 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)); } - 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); } - 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);}); }
处理返回结果
- DispatcherHandler#handleResult
private Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {return getResultHandler(result).handleResult(exchange, result) ; } - DispatcherHandler#getResultHandler => ResponseBodyResultHandler
- 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框架,性能彪悍,支持的协…...
DevEco Studio设置Nodejs提示路径只能包含英文、数字、下划线等
安装DevEco Studio 3.1.1 Release 设置Nodejs路径使用nodejs默认安装路径 (C:\Program Files\nodejs) 提示只能包含英文、数字、下划线等 , 不想在安装nodejs请往下看 nodejs默认路径报错 修改配置文件 1、退出DevEco Studio 2、打开配置文件 cmd控制台…...
大模型 Decoder 的生成策略
本文将介绍以下内容: IntroductionGreedy Searchbeam searchSamplingTop-K SamplingTop-p (nucleus) sampling总结 一、Introduction 1、简介 近年来,由于在数百万个网页数据上训练的大型基于 Transformer 的语言模型的兴起,开放式语言生…...
队列和栈相互实现
相关题目 225. 用队列实现栈:弹出元素时,将对首的元素出列加到队尾,直到只剩下初始队列时队尾一个元素为止,然后弹出这个元素,即可实现LIFO 232. 用栈实现队列:用两个栈实现队列的功能,出栈时&a…...
Node.js 是如何处理请求的
前言:在服务器软件中,如何处理请求是非常核心的问题。不管是底层架构的设计、IO 模型的选择,还是上层的处理都会影响一个服务器的性能,本文介绍 Node.js 在这方面的内容。 TCP 协议的核心概念 要了解服务器的工作原理首先需要了…...
数据结构与算法之堆: Leetcode 215. 数组中的第K个最大元素 (Typescript版)
数组中的第K个最大元素 https://leetcode.cn/problems/kth-largest-element-in-an-array/ 描述 给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。…...
SpringBoot快速入门
搭建SpringBoot工程,定义hello方法,返回“Hello SpringBoot” ②导入springboot工程需要继承的父工程;以及web开发的起步依赖。 ③编写Controller ④引导类就是SpringBoot项目的一个入口。 写注解写main方法调用run方法 快速构建SpringBoo…...
深度学习笔记_4、CNN卷积神经网络+全连接神经网络解决MNIST数据
1、首先,导入所需的库和模块,包括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 证书的优势
随着网络威胁日益增多,保护网站和用户安全已成为每个企业和组织的重要任务。在众多SSL证书类型中,OV(Organization Validation)证书以其独特的优势备受关注。让我们深入探究OV证书的优势所在,为网站安全搭建坚实的防线…...
一篇博客学会系列(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:完成“因类型而异”的行为;constructor:明确类型时构造函数;virtual constructor:视其获得的输入,可产生不同的类型对象。 //假如写一个软件,用来处理时事…...
蓝牙核心规范(V5.4)11.6-LE Audio 笔记之初识音频位置和通道分配
专栏汇总网址:蓝牙篇之蓝牙核心规范学习笔记(V5.4)汇总_蓝牙核心规范中文版_心跳包的博客-CSDN博客 爬虫网站无德,任何非CSDN看到的这篇文章都是盗版网站,你也看不全。认准原始网址。!!! 音频位置 在以前的每个蓝牙音频规范中,只有一个蓝牙LE音频源和一个蓝牙LE音频接…...
mysql双主+双从集群连接模式
架构图: 详细内容参考: 结果展示: 178.119.30.14(主) 178.119.30.15(主) 178.119.30.16(从) 178.119.30.17(从)...
嵌入式中如何用C语言操作sqlite3(07)
sqlite3编程接口非常多,对于初学者来说,我们暂时只需要掌握常用的几个函数,其他函数自然就知道如何使用了。 数据库 本篇假设数据库为my.db,有数据表student。 nonamescore4嵌入式开发爱好者89.0 创建表格语句如下: CREATE T…...
RandomForestClassifier 与 GradientBoostingClassifier 的区别
RandomForestClassifier(随机森林分类器)和GradientBoostingClassifier(梯度提升分类器)是两种常用的集成学习方法,它们之间的区别分以下几点。 1、基础算法 RandomForestClassifier:随机森林分类器是基于…...
计组——I/O方式
一、程序查询方式 CPU不断轮询检查I/O控制器中“状态寄存器”,检测到状态为“已完成”之后,再从数据寄存器取出输入数据。 过程: 1.CPU执行初始化程序,并预置传送参数;设置计数器、设置数据首地址。 2. 向I/O接口发…...
jsbridge实战2:Swift和h5的jsbridge通信
[[toc]] demo1: 文本通信 h5 -> app 思路: h5 全局属性上挂一个变量app 接收这个变量的内容关键API: navigation代理 navigationAction.request.url?.absoluteString // 这个变量挂载在 request 的 url 上 ,在浏览器实际无法运行,因…...
集合原理简记
HashMap 无论在构造函数是否指定数组长度,进行的都是延迟初始化 构造函数作用: 阈值:threshold,每次<<1 ,数组长度 负载因子 无参构造:设置默认的负载因子 有参:可以指定初始容量或…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...
基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
