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

谷歌浏览器插件

项目中有时候会用到插件 sync-cookie-extension1.0.0&#xff1a;开发环境同步测试 cookie 至 localhost&#xff0c;便于本地请求服务携带 cookie 参考地址&#xff1a;https://juejin.cn/post/7139354571712757767 里面有源码下载下来&#xff0c;加在到扩展即可使用FeHelp…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域&#xff0c;准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具&#xff0c;正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...