undertow服务器初始化
springboot整合undertow服务器的源码从老生常谈的createWebServer
方法谈起。spring会在生成所有bean后到创建web容器,此时会到容器找到ServletWebServerFactory
接口bean,spring会根据引入的框架确定生成的ServletWebServerFactory
,我们在maven中引入了undertow后,由UndertowServletWebServerFactory
实现。
private void createWebServer() {WebServer webServer = this.webServer;ServletContext servletContext = getServletContext();if (webServer == null && servletContext == null) {ServletWebServerFactory factory = getWebServerFactory();this.webServer = factory.getWebServer(getSelfInitializer());getBeanFactory().registerSingleton("webServerGracefulShutdown",new WebServerGracefulShutdownLifecycle(this.webServer));getBeanFactory().registerSingleton("webServerStartStop",new WebServerStartStopLifecycle(this, this.webServer));}else if (servletContext != null) {try {getSelfInitializer().onStartup(servletContext);}catch (ServletException ex) {throw new ApplicationContextException("Cannot initialize servlet context", ex);}}initPropertySources();}
UndertowServletWebServerFactory
类的getWebServer
会创建WebServer。
public WebServer getWebServer(ServletContextInitializer... initializers) {Builder builder = this.delegate.createBuilder(this);DeploymentManager manager = createManager(initializers);return getUndertowWebServer(builder, manager, getPort());}
先用默认的配置构建Builder对象,再使用读取的配置。
Builder createBuilder(AbstractConfigurableWebServerFactory factory) {Ssl ssl = factory.getSsl();InetAddress address = factory.getAddress();int port = factory.getPort();Builder builder = Undertow.builder();if (this.bufferSize != null) {builder.setBufferSize(this.bufferSize);}if (this.ioThreads != null) {builder.setIoThreads(this.ioThreads);}if (this.workerThreads != null) {builder.setWorkerThreads(this.workerThreads);}if (this.directBuffers != null) {builder.setDirectBuffers(this.directBuffers);}if (ssl != null && ssl.isEnabled()) {new SslBuilderCustomizer(factory.getPort(), address, ssl, factory.getSslStoreProvider()).customize(builder);Http2 http2 = factory.getHttp2();if (http2 != null) {builder.setServerOption(UndertowOptions.ENABLE_HTTP2, http2.isEnabled());}}else {builder.addHttpListener(port, (address != null) ? address.getHostAddress() : "0.0.0.0");}builder.setServerOption(UndertowOptions.SHUTDOWN_TIMEOUT, 0);for (UndertowBuilderCustomizer customizer : this.builderCustomizers) {customizer.customize(builder);}return builder;}
之后再注册Servlet和Filter过滤器到容器中。
public void deploy() {final DeploymentInfo deploymentInfo = originalDeployment.clone();if (deploymentInfo.getServletStackTraces() == ServletStackTraces.ALL) {UndertowServletLogger.REQUEST_LOGGER.servletStackTracesAll(deploymentInfo.getDeploymentName());}deploymentInfo.validate();final DeploymentImpl deployment = new DeploymentImpl(this, deploymentInfo, servletContainer);this.deployment = deployment;final ServletContextImpl servletContext = new ServletContextImpl(servletContainer, deployment);deployment.setServletContext(servletContext);handleExtensions(deploymentInfo, servletContext);final List<ThreadSetupHandler> setup = new ArrayList<>();setup.add(ServletRequestContextThreadSetupAction.INSTANCE);setup.add(new ContextClassLoaderSetupAction(deploymentInfo.getClassLoader()));setup.addAll(deploymentInfo.getThreadSetupActions());deployment.setThreadSetupActions(setup);deployment.getServletPaths().setWelcomePages(deploymentInfo.getWelcomePages());if (deploymentInfo.getDefaultEncoding() != null) {deployment.setDefaultCharset(Charset.forName(deploymentInfo.getDefaultEncoding()));}if(deploymentInfo.getDefaultRequestEncoding() != null) {deployment.setDefaultRequestCharset(Charset.forName(deploymentInfo.getDefaultRequestEncoding()));} else if (deploymentInfo.getDefaultEncoding() != null) {deployment.setDefaultRequestCharset(Charset.forName(deploymentInfo.getDefaultEncoding()));}if(deploymentInfo.getDefaultResponseEncoding() != null) {deployment.setDefaultResponseCharset(Charset.forName(deploymentInfo.getDefaultResponseEncoding()));} else if (deploymentInfo.getDefaultEncoding() != null) {deployment.setDefaultResponseCharset(Charset.forName(deploymentInfo.getDefaultEncoding()));}handleDeploymentSessionConfig(deploymentInfo, servletContext);deployment.setSessionManager(deploymentInfo.getSessionManagerFactory().createSessionManager(deployment));deployment.getSessionManager().setDefaultSessionTimeout(deploymentInfo.getDefaultSessionTimeout());try {deployment.createThreadSetupAction(new ThreadSetupHandler.Action<Void, Object>() {@Overridepublic Void call(HttpServerExchange exchange, Object ignore) throws Exception {final ApplicationListeners listeners = createListeners();listeners.start();deployment.setApplicationListeners(listeners);//now create the servlets and filters that we know about. We can still get more latercreateServletsAndFilters(deployment, deploymentInfo);//first initialize the temp dirinitializeTempDir(servletContext, deploymentInfo);//then run the SCI'sfor (final ServletContainerInitializerInfo sci : deploymentInfo.getServletContainerInitializers()) {final InstanceHandle<? extends ServletContainerInitializer> instance = sci.getInstanceFactory().createInstance();try {instance.getInstance().onStartup(sci.getHandlesTypes(), servletContext);} finally {instance.release();}}deployment.getSessionManager().registerSessionListener(new SessionListenerBridge(deployment, listeners, servletContext));for(SessionListener listener : deploymentInfo.getSessionListeners()) {deployment.getSessionManager().registerSessionListener(listener);}initializeErrorPages(deployment, deploymentInfo);initializeMimeMappings(deployment, deploymentInfo);listeners.contextInitialized();//runHttpHandler wrappedHandlers = ServletDispatchingHandler.INSTANCE;wrappedHandlers = wrapHandlers(wrappedHandlers, deploymentInfo.getInnerHandlerChainWrappers());wrappedHandlers = new RedirectDirHandler(wrappedHandlers, deployment.getServletPaths());if(!deploymentInfo.isSecurityDisabled()) {HttpHandler securityHandler = setupSecurityHandlers(wrappedHandlers);wrappedHandlers = new PredicateHandler(DispatcherTypePredicate.REQUEST, securityHandler, wrappedHandlers);}HttpHandler outerHandlers = wrapHandlers(wrappedHandlers, deploymentInfo.getOuterHandlerChainWrappers());wrappedHandlers = new PredicateHandler(DispatcherTypePredicate.REQUEST, outerHandlers, wrappedHandlers);wrappedHandlers = handleDevelopmentModePersistentSessions(wrappedHandlers, deploymentInfo, deployment.getSessionManager(), servletContext);MetricsCollector metrics = deploymentInfo.getMetricsCollector();if(metrics != null) {wrappedHandlers = new MetricsChainHandler(wrappedHandlers, metrics, deployment);}if( deploymentInfo.getCrawlerSessionManagerConfig() != null ) {wrappedHandlers = new CrawlerSessionManagerHandler(deploymentInfo.getCrawlerSessionManagerConfig(), wrappedHandlers);}final ServletInitialHandler servletInitialHandler = SecurityActions.createServletInitialHandler(deployment.getServletPaths(), wrappedHandlers, deployment, servletContext);HttpHandler initialHandler = wrapHandlers(servletInitialHandler, deployment.getDeploymentInfo().getInitialHandlerChainWrappers());initialHandler = new HttpContinueReadHandler(initialHandler);if(deploymentInfo.getUrlEncoding() != null) {initialHandler = Handlers.urlDecodingHandler(deploymentInfo.getUrlEncoding(), initialHandler);}deployment.setInitialHandler(initialHandler);deployment.setServletHandler(servletInitialHandler);deployment.getServletPaths().invalidate(); //make sure we have a fresh set of servlet pathsservletContext.initDone();return null;}}).call(null, null);} catch (Exception e) {throw new RuntimeException(e);}//any problems with the paths won't get detected until the data is initialize//so we force initialization heredeployment.getServletPaths().initData();for(ServletContextListener listener : deploymentInfo.getDeploymentCompleteListeners()) {listener.contextInitialized(new ServletContextEvent(servletContext));}state = State.DEPLOYED;}
到WebServer
接口的start()
方法就会启动undertow服务器了,本质就是通过XNIO框架监听服务器端口号,接收请求并处理。处理请求时的io线程模型分数据处理线程和业务处理线程。
public synchronized void start() {UndertowLogger.ROOT_LOGGER.infof("starting server: %s", Version.getFullVersionString());xnio = Xnio.getInstance(Undertow.class.getClassLoader());channels = new ArrayList<>();try {if (internalWorker) {worker = xnio.createWorker(OptionMap.builder().set(Options.WORKER_IO_THREADS, ioThreads).set(Options.CONNECTION_HIGH_WATER, 1000000).set(Options.CONNECTION_LOW_WATER, 1000000).set(Options.WORKER_TASK_CORE_THREADS, workerThreads).set(Options.WORKER_TASK_MAX_THREADS, workerThreads).set(Options.TCP_NODELAY, true).set(Options.CORK, true).addAll(workerOptions).getMap());}OptionMap socketOptions = OptionMap.builder().set(Options.WORKER_IO_THREADS, worker.getIoThreadCount()).set(Options.TCP_NODELAY, true).set(Options.REUSE_ADDRESSES, true).set(Options.BALANCING_TOKENS, 1).set(Options.BALANCING_CONNECTIONS, 2).set(Options.BACKLOG, 1000).addAll(this.socketOptions).getMap();OptionMap serverOptions = OptionMap.builder().set(UndertowOptions.NO_REQUEST_TIMEOUT, 60 * 1000).addAll(this.serverOptions).getMap();ByteBufferPool buffers = this.byteBufferPool;if (buffers == null) {buffers = new DefaultByteBufferPool(directBuffers, bufferSize, -1, 4);}listenerInfo = new ArrayList<>();for (ListenerConfig listener : listeners) {UndertowLogger.ROOT_LOGGER.debugf("Configuring listener with protocol %s for interface %s and port %s", listener.type, listener.host, listener.port);final HttpHandler rootHandler = listener.rootHandler != null ? listener.rootHandler : this.rootHandler;OptionMap socketOptionsWithOverrides = OptionMap.builder().addAll(socketOptions).addAll(listener.overrideSocketOptions).getMap();......if (listener.type == ListenerType.HTTP) {HttpOpenListener openListener = new HttpOpenListener(buffers, undertowOptions);HttpHandler handler = rootHandler;if (http2) {handler = new Http2UpgradeHandler(handler);}openListener.setRootHandler(handler);final ChannelListener<StreamConnection> finalListener;if (listener.useProxyProtocol) {finalListener = new ProxyProtocolOpenListener(openListener, null, buffers, OptionMap.EMPTY);} else {finalListener = openListener;}ChannelListener<AcceptingChannel<StreamConnection>> acceptListener = ChannelListeners.openListenerAdapter(finalListener);AcceptingChannel<? extends StreamConnection> server = worker.createStreamConnectionServer(new InetSocketAddress(Inet4Address.getByName(listener.host), listener.port), acceptListener, socketOptionsWithOverrides);server.resumeAccepts();channels.add(server);listenerInfo.add(new ListenerInfo("http", server.getLocalAddress(), openListener, null, server));} ......}
相关文章:
undertow服务器初始化
springboot整合undertow服务器的源码从老生常谈的createWebServer方法谈起。spring会在生成所有bean后到创建web容器,此时会到容器找到ServletWebServerFactory接口bean,spring会根据引入的框架确定生成的ServletWebServerFactory,我们在mave…...
LeetCode9:回文数
原题地址:. - 力扣(LeetCode) 题目描述: 给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。 回文数 是指正序(从左向右)和倒序ÿ…...
模板语法(2)
一、循环 在模板中可以用v-for指令来循环数组,对象等。 1. 循环数组 <script setup name"App">import { reactive } from "vue"const books reactive([{title: 三国演义,author: 罗贯中}, {title: 水浒传,author: 施耐庵}, {title: 西…...

从头学PHP之数组输出基本函数
上期我们讲到了数组,数组是个特殊的变量,在程序中的重要程度很高,大部分数据处理的时候会用到这种特殊的变量,那么现在让我们继续深入一下吧。 上期我们打印出了数组的值,用print_r()或者var_dump()这俩函数࿰…...

基于SSM+小程序的4S店客户管理系统(汽车2)
👉文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 4S店客户管理系统主要包括管理员、用户、门店三个权限角色 1、管理员实现了首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、…...

ZYNQ AXI_Timer 中断
REVIEW 关于ZYNQ中断: ZYNQ PS_GPIO中断-CSDN博客 ZYNQ AXI_GPIO_INT-CSDN博客 ZYNQ 定时器中断-CSDN博客 在一些应用场景中,可能需要使用到多个定时器,除了选择使用 PS 侧其他定时器外,也可以使用 PL 侧逻辑定时器。 1. 今日摸鱼…...

UE5之5.4 第一人称示例代码阅读2 子弹发射逻辑
TP_WeaponComponent.h 看看头文件 暴露了attach weapon和fire给蓝图 这两个函数意义一看名字吧,就是捡起来枪的时候执行,一个就是发射子弹的时候执行 #pragma once#include "CoreMinimal.h" #include "Components/SkeletalMeshComponen…...
Python 实现日期计算与日历格式化输出(万年历)
目录 一、引言 二、需求分析 三、实现思路 四、代码实现 五、代码分析 六、测试与验证 七、总结与展望 在日常的编程中,我们经常会遇到与日期相关的问题,比如计算两个日期之间的天数差、确定某个特定日期是星期几以及格式化输出日历等。本文将详细…...

10.28.2024刷华为OD C题型
文章目录 HJ9HJ10HJ11HJ13HJ17 HJ9 HJ10 HJ11 HJ13 HJ17...

映射问题的解决办法(mybaitis)
最初我用的是注解来操控数据库(注释掉的部分) Mapper public interface ThreadMapper {// Select("SELECT * FROM thread LIMIT #{page}, #{size}")List<Thread> getListByPage(Param("page") int page, Param("size&qu…...
关于机器学习方向学习的一些建议(过来人)
以下是关于机器学习方向学习的一些建议: 一、扎实的数学基础 线性代数 线性代数是机器学习的基石。矩阵运算在数据表示、模型参数计算等方面无处不在。例如,在多元线性回归中,我们用矩阵来表示自变量和因变量之间的关系。像最小二乘法求解回…...
【云原生】云原生后端:网络架构详解
目录 引言一、微服务间的通信1.1 通信方式概览1.2 HTTP/REST1.3 gRPC1.4 消息队列1.5 GraphQL 二、API网关2.1 API网关架构示例2.2 API网关实现示例 三、服务发现3.1 服务发现实现示例3.2 服务发现的优势 四、网络安全4.1 网络安全最佳实践4.2 网络安全架构示例 总结参考资料 引…...

期货资管子系统框架设计JS路径及源代码分享
期货资管子系统框架设计JS路径及源代码分享 随着期货资管子系统前端技术的飞速发展,JavaScript(JS)及其相关框架已成为构建这类系统的重要工具。本文将详细介绍一个期货资管子系统框架的设计思路,并分享部分JS路径及源代码&#…...

【YOLO 系列】基于YOLO的工业自动化轴承缺陷检测系统【python源码+Pyqt5界面+数据集+训练代码】
前言 轴承作为机械设备中的关键部件,其性能直接影响到设备的稳定性和寿命。轴承缺陷的早期检测对于预防设备故障、减少维护成本和提高生产效率至关重要。然而,传统的轴承缺陷检测方法往往依赖于人工检查,这不仅效率低下,而且容易…...

Word中Normal.dotm样式模板文件
Normal.dotm文档 首先将自己电脑中C:\Users\自己电脑用户名\AppData\Roaming\Microsoft\Templates路径下的Normal.dotm文件做备份,在下载本文中的Normal.dotm文件,进行替换,重新打开word即可使用。 字体样式如下(可自行修改&#…...

生成式 AI 与向量搜索如何扩大零售运营:巨大潜力尚待挖掘
在竞争日益激烈的零售领域,行业领导者始终在探索革新客户体验和优化运营的新途径,而生成式 AI 和向量搜索在这方面将大有可为。从个性化营销到高效库存管理,二者在零售领域的诸多应用场景中都展现出变革性潜力,已成为保持行业领先…...

WonderWorld:斯坦福与 MIT 联手打造实时交互生成图像,单图秒变 3D 虚拟世界
❤️ 如果你也关注大模型与 AI 的发展现状,且对大模型应用开发非常感兴趣,我会快速跟你分享最新的感兴趣的 AI 应用和热点信息,也会不定期分享自己的想法和开源实例,欢迎关注我哦! 🥦 微信公众号ÿ…...

2024年【制冷与空调设备安装修理】考试内容及制冷与空调设备安装修理最新解析
题库来源:安全生产模拟考试一点通公众号小程序 制冷与空调设备安装修理考试内容是安全生产模拟考试一点通总题库中生成的一套制冷与空调设备安装修理最新解析,安全生产模拟考试一点通上制冷与空调设备安装修理作业手机同步练习。2024年【制冷与空调设备…...
PHP const 和 define主要区别
在PHP中,const 和 define 都用于定义常量,但它们有一些关键的区别。以下是它们之间的主要不同点: 定义方式: const:在定义常量时,不需要使用函数形式,而是直接赋值。 const MY_CONSTANT som…...
期中前学习复习总结
期中前终于把每一科的本质给搞明白了。这篇文章也将各学科剖分为两部分。 目录 本质 学法 从问题或条件出发思考问题 从条件出发思考问题 从结论/问题出发思考问题 整理知识与反向押题法 反向押题法 本质 作者是一个理科脑,什么都觉得只要我脑子够新东西我…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...

.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

基于IDIG-GAN的小样本电机轴承故障诊断
目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) 梯度归一化(Gradient Normalization) (2) 判别器梯度间隙正则化(Discriminator Gradient Gap Regularization) (3) 自注意力机制(Self-Attention) 3. 完整损失函数 二…...

搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...

Vue ③-生命周期 || 脚手架
生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来) Vue生命周期: 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...
文件上传漏洞防御全攻略
要全面防范文件上传漏洞,需构建多层防御体系,结合技术验证、存储隔离与权限控制: 🔒 一、基础防护层 前端校验(仅辅助) 通过JavaScript限制文件后缀名(白名单)和大小,提…...

leetcode_69.x的平方根
题目如下 : 看到题 ,我们最原始的想法就是暴力解决: for(long long i 0;i<INT_MAX;i){if(i*ix){return i;}else if((i*i>x)&&((i-1)*(i-1)<x)){return i-1;}}我们直接开始遍历,我们是整数的平方根,所以我们分两…...
python打卡第47天
昨天代码中注意力热图的部分顺移至今天 知识点回顾: 热力图 作业:对比不同卷积层热图可视化的结果 def visualize_attention_map(model, test_loader, device, class_names, num_samples3):"""可视化模型的注意力热力图,展示模…...

RabbitMQ 各类交换机
为什么要用交换机? 交换机用来路由消息。如果直发队列,这个消息就被处理消失了,那别的队列也需要这个消息怎么办?那就要用到交换机 交换机类型 1,fanout:广播 特点 广播所有消息:将消息…...