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

专做专业课视频的网站/上海比较大的优化公司

专做专业课视频的网站,上海比较大的优化公司,贝壳网二手房出售信息,自己做电影网站需要的成本目录 代码入口上下文容器 加载web容器WebServercreateWebServergetWebServerFactory():getWebServer(): 执行WebServer#start自动配置读取配置修改配置 代码入口 上下文容器 SpringApplication.run(App.class); //追踪下去发现 context createApplicationContext…

目录

    • 代码入口
      • 上下文容器
    • 加载web容器
      • WebServer
      • createWebServer
      • getWebServerFactory():
      • getWebServer():
    • 执行WebServer#start
    • 自动配置
      • 读取配置
      • 修改配置

代码入口

上下文容器

SpringApplication.run(App.class);
//追踪下去发现
context = createApplicationContext();createApplicationContext()return this.applicationContextFactory.create(this.webApplicationType);这里用了策略模式:
读取 interface org.springframework.boot.ApplicationContextFactory 的实现
根据 webApplicationType 匹配对应的处理
case : WebApplicationType.REACTIVE : return new AnnotationConfigReactiveWebServerApplicationContext();
case : WebApplicationType.SERVLET : return new AnnotationConfigServletWebServerApplicationContext();然后就创建了:
org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext

webApplicationType 获取

//this.webApplicationType是在new SpringApplication()的时候赋值的
this.webApplicationType = WebApplicationType.deduceFromClasspath();WebApplicationType.deduceFromClasspath():if (classpath中 有 org.springframework.web.reactive.DispatcherHandler 
且 没有 org.springframework.web.servlet.DispatcherServlet 
且 没有 org.glassfish.jersey.servlet.ServletContainer) {return WebApplicationType.REACTIVE;
}//有 spring-web的依赖则有
if (classpath中 没有 javax.servlet.Servlet) {return WebApplicationType.NONE;
}
if (classpath中 没有 org.springframework.web.context.ConfigurableWebApplicationContext) {return WebApplicationType.NONE;
}
return WebApplicationType.SERVLET;

加载web容器

首先我们知道了现在的上下文是AnnotationConfigServletWebServerApplicationContext
看一下依赖
在这里插入图片描述

执行 org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefreshorg.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#createWebServer
来创建一个WebServer

WebServer

我们先来分析下这个类
这个类是一个接口

void start() throws WebServerException;
void stop() throws WebServerException;
//返回监听端口
int getPort();
//优雅关闭
void shutDownGracefully(GracefulShutdownCallback callback);

createWebServer

//看下容器中是否有webServer 这里是没有的
WebServer webServer = this.webServer;
ServletContext servletContext = this.servletContext;
if (webServer == null && servletContext == null) {//获取WebServerFactory 这里会确定 web容器是 tomcat 还是其他ServletWebServerFactory factory = getWebServerFactory();//这一步就初始化容器了 设置端口啥的//这里要注意了 getWebServer入参是ServletContextInitializer 这是一个函数类//也就是说只是设置了行为而不需要执行 先执行了getWebServerthis.webServer = factory.getWebServer(getSelfInitializer());//注册优雅关闭getBeanFactory().registerSingleton("webServerGracefulShutdown",new WebServerGracefulShutdownLifecycle(this.webServer));//注册启动 关闭getBeanFactory().registerSingleton("webServerStartStop",new WebServerStartStopLifecycle(this, this.webServer));
}

getWebServerFactory():

//获取Bean工厂里ServletWebServerFactory的BeanName
//这里获取的是 tomcatServletWebServerFactory
String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
//这里会校验 容器中有且只能有一个ServletWebServerFactory类
if (beanNames.length == 0) {throw new MissingWebServerFactoryBeanException()}
if (beanNames.length > 1) {throw new ApplicationContextException()}
return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);

为什么获取的是 tomcatServletWebServerFactory 呢?

一般找不到在哪里注入的Bean的时候就可以试一下搜索XXXAutoConfiguration
就是利用自动配置类 SPI机制加载 ServletWebServerFactoryAutoConfiguration
其中引入了 
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class
ServletWebServerFactoryConfiguration.EmbeddedJetty.class
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class
但是这三个类都有各自创建的条件比如tomcat@Configuration(proxyBeanMethods = false)
// 这三个类在 类加载器里都存在
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
//要是有用户自定义的 ServletWebServerFactory 类型的Bean就不创建
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedTomcat {//这里的ObjectProvider 意思就是有了就设置进去,没了设置一个内容为空的对象//给对Tomcat进行自定义设置的一个扩展,再配置无法满足需求的时候@BeanTomcatServletWebServerFactory tomcatServletWebServerFactory(ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,ObjectProvider<TomcatContextCustomizer> contextCustomizers,ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();factory.getTomcatConnectorCustomizers().addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));factory.getTomcatContextCustomizers().addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));factory.getTomcatProtocolHandlerCustomizers().addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));return factory;}
}

注意
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
这个注解里依赖的 class即使不存在也没关系 因为编译运行都不会报错
因为本来我们应用里依赖的就是 jar包
jar包就是编译好的class文件,所以不会再重复编译了
运行的时候也不是直接反射,而是利用ASM技术直接读的字节码获取引用类的全类名
然后调用类加载器加载,加载不到就是没有

getWebServer():

Tomcat tomcat = new Tomcat();
然后进行各种设置 下面三个日志就是这一步打印的
o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
o.apache.catalina.core.StandardService   : Starting service [Tomcat]
org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.71]总之就是创建了服务 但是没有真正的启动因为关系是这样的 上下文的refresh()方法中
// Initialize other special beans in specific context subclasses.
// 此时还在这里
onRefresh();// Check for listener beans and register them.
registerListeners();// Instantiate all remaining (non-lazy-init) singletons.
// 创建 非懒加载的单例bean
finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.
// 最后一步 到这里 所有Bean都已经ok了 可以提供服务出来了
finishRefresh();

执行WebServer#start

finishRefresh()getLifecycleProcessor().onRefresh() 中的 onRefresh()
onRefresh()startBeans(true);startBeans(true) :
获取beanFactory 中所有的 Lifecycle.class 类型的Bean 设置到 Map<String, Lifecycle> lifecycleBeansMap<Integer, LifecycleGroup> phases = new TreeMap<>();
遍历 lifecycleBeans : (beanName, bean){if (bean instanceof SmartLifecycle && bean.isAutoStartup())) {int phase = getPhase(bean);//这个就是说如果map的value已存在 那么就add(beanName, bean)//不存在就创建phases.computeIfAbsent(phase,p -> new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly)).add(beanName, bean);if (!phases.isEmpty()) {//这里就执行了 bean.start();//也就是日志:o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''phases.values().forEach(LifecycleGroup::start);}}
}

自动配置

我们经常用的比如改端口

server.prot=8080

是怎么实现的呢?

读取配置

//这个注释意思是如果这个类没有加载 那么ServerProperties这个类也不需要加载了
@EnableConfigurationProperties(ServerProperties.class)
public class ServletWebServerFactoryAutoConfiguration {}@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {private Integer port;...
}

这里就是读取配置
那再哪里修改的呢

修改配置

@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,...}
public class ServletWebServerFactoryAutoConfiguration {}BeanPostProcessorsRegistrar 在 registerBeanDefinitions 方法中注册了WebServerFactoryCustomizerBeanPostProcessorWebServerFactoryCustomizerBeanPostProcessor 的 postProcessBeforeInitialization 方法中遍历所有 WebServerFactoryCustomizer.class 类的Bean : customizer {customizer.customize(webServerFactory);
}

哪里注册了 WebServerFactoryCustomizer ?

public class ServletWebServerFactoryAutoConfiguration {@Beanpublic ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties){...}...
}org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryCustomizer#customize 中@Override
public void customize(ConfigurableServletWebServerFactory factory) {PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();//存在配置 则调用setPortmap.from(this.serverProperties::getPort).to(factory::setPort);map.from(this.serverProperties::getAddress).to(factory::setAddress);...
}也就是调用了ConfigurableServletWebServerFactory 的setPort

最终读取

org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#getWebServer 中
Tomcat tomcat = new Tomcat();
...
Connector connector = new Connector(this.protocol);
...
customizeConnector(connector);其中customizeConnector(connector)int port = Math.max(getPort(), 0);
connector.setPort(port);其中getPort():
获取属性port 默认是 8080

相关文章:

001-Spring boot 启动内置Web容器分析

目录 代码入口上下文容器 加载web容器WebServercreateWebServergetWebServerFactory()&#xff1a;getWebServer(): 执行WebServer#start自动配置读取配置修改配置 代码入口 上下文容器 SpringApplication.run(App.class); //追踪下去发现 context createApplicationContext…...

【Cocos Creator 项目实战 】消灭星星加强版(附带完整源码工程)

本文乃Siliphen原创&#xff0c;转载请注明出处 目录 概述 游戏整体流程 游戏框架设计 单一职责的类 主要流程控制类 核心玩法模块 UI&#xff1a; 游戏世界&#xff1a; 本文项目的代码组织结构 作者项目实践总结 场景只有一个入口脚本 尽量少在节点上挂载脚本 构…...

2023软件测试岗必问的100个面试题【含答案】

一、测试理论 1.什么是软件测试&#xff1f; 答&#xff1a;软件测试是通过执行预定的步骤和使用指定的数据&#xff0c;以确定软件系统在特定条件下是否满足预期的行为。 2.测试驱动开发&#xff08;TDD&#xff09;是什么&#xff1f; 答&#xff1a;测试驱动开发是一种开…...

MediaExtractor MediaCodec手动解码播放音乐

MediaExtractor MediaCodec手动解码播放音乐,笔记 private class DecodeAudio implements Runnable {Overridepublic void run() {//开始播放pcmaudioTrack.play();MediaExtractor extractor null;MediaCodec codec null;Log.i(TAG, "run: init");FileOutputStrea…...

element表格+表单+表单验证结合运用

目录​​​​​​​ 一、结果展示 二、实现代码 一、结果展示 1、图片 2、描述 table中放form表单&#xff0c;放输入框或下拉框或多选框等&#xff1b; 点击添加按钮&#xff0c;首先验证表单&#xff0c;如果存在没填的就验证提醒&#xff0c;都填了就向下添加一行表单表…...

亚马逊云科技发布Amazon HealthScribe,使用生成式AI技术实现临床文档的自动生成

近日&#xff0c;亚马逊云科技在纽约峰会上推出了Amazon HealthScribe&#xff0c;该服务符合HIPAA&#xff08;《健康保险流通与责任法案》&#xff09;的相关要求&#xff0c;可为医疗软件供应商提供一种基于语音和文字识别的生成式AI技术&#xff0c;帮助其创建能够自动生成…...

Windows11安装Linux子系统,并实现服务自启动,局域网访问,磁盘挂载

Windows11安装Linux子系统&#xff0c;并实现服务自启动&#xff0c;局域网访问&#xff0c;磁盘挂载 一、准备工作二、安装Linux子系统(wsl2)三、为Linux子系统设置桥接网络检查wsl版本在 Hyper-V 管理器中创建虚拟交换机创建 WSL 配置文件启动wsl 四、设置Windows开机自启动L…...

【Git】保姆级详解:Git配置SSH Key(密钥和公钥)到github

博主简介&#xff1a;22级计算机科学与技术本科生一枚&#x1f338;博主主页&#xff1a;是瑶瑶子啦每日一言&#x1f33c;: “当人们做不到一些事情的时候&#xff0c;他们会对你说你也同样不能。”——《当幸福来敲门》 克里斯加德纳 Git配置SSH Key 一、什么是Git?二、什么…...

离线环境conda虚拟环境备份迁移--conda pack问题

1.第一步&#xff1a;创建虚拟环境 conda create -n pyenv --clone base 或者 conda create -n pyenv python3.8.5 --offline 命令执行结束&#xff0c;在路径/xxxx/anaconda/envs 下看到pyenv 或者 conda info --envs 查看罗列虚拟环境 2.第二步&#xff1a;打包环境 conda …...

挂载 IK 分词器至 Elasticsearch Docker 容器 - Docker Docker Compose 教程

简介 本博客将讲解如何在 Docker 和 Docker-Compose 中运行 Elasticsearch&#xff0c;并挂载 IK 分词器。 步骤 一、快速运行Elasticsearch:8.1.3 1.首先&#xff0c;我们需要创建一个新的 Docker 网络&#xff1a;"elastic"。这个网络会提供给我们接下来所要创…...

7.6 通俗易懂解读残差网络ResNet 手撕ResNet

一.举例通俗解释ResNet思想 假设你正在学习如何骑自行车&#xff0c;并且想要骑到一个遥远的目的地。你可以选择直接骑到目的地&#xff0c;也可以选择在途中设置几个“中转站”&#xff0c;每个中转站都会告诉你如何朝着目的地前进。 在传统的神经网络中&#xff0c;就好比只…...

robotframework+selenium 进行webui页面自动化测试

robotframework其实就是一个自动化的框架&#xff0c;想要进行什么样的自动化测试&#xff0c;就需要在这框架上添加相应的库文件&#xff0c;而用于webui页面自动化测试的就是selenium库. 关于robotframework框架的搭建我这里就不说了&#xff0c;今天就给大家根据一个登录的实…...

手机突然无法获取ip地址

在日常生活中&#xff0c;我们对手机的依赖越来越大&#xff0c;尤其是在联网方面。然而&#xff0c;有时候我们可能会遇到手机无法获取IP地址的问题&#xff0c;这给我们的正常使用带来了很多不便。当我们的手机无法获得IP地址时&#xff0c;我们将无法连接到互联网或局域网&a…...

C++——关于命名空间

写c项目时&#xff0c;大家常用到的一句话就是&#xff1a; using namespace std; 怎么具体解析这句话呢&#xff1f; 命名冲突&#xff1a; 在c语言中&#xff0c;我们有变量的命名规范&#xff0c;如果一个变量名或者函数名和某个库里面自带的库函数或者某个关键字重名&…...

怎么进行流程图制作?用这个工具制作很方便

怎么进行流程图制作&#xff1f;流程图是一种非常有用的工具&#xff0c;可以帮助我们更好地理解和展示各种复杂的业务流程和工作流程。它可以将复杂的过程简化为易于理解的图形和文本&#xff0c;使得人们更容易理解和跟踪整个流程。因此&#xff0c;制作流程图是在日常工作中…...

【ChatGPT 指令大全】怎么使用ChatGPT来辅助学习英语

在当今全球化的社会中&#xff0c;英语已成为一门世界性的语言&#xff0c;掌握良好的英语技能对个人和职业发展至关重要。而借助人工智能的力量&#xff0c;ChatGPT为学习者提供了一个有价值的工具&#xff0c;可以在学习过程中提供即时的帮助和反馈。在本文中&#xff0c;我们…...

Ubuntu20配置仅主机网络

Ubuntu20配置仅主机网络&#xff0c;使虚拟机与物理机网络联通且配置固定IP 进入终端&#xff1a;vim /etc/netplan/01-network-manager-all.yaml 修改为&#xff1a; network:ethernets:enp0s8:addresses: [192.168.138.108/24]dhcp4: false optional: truegateway4: 192.…...

调整奇数偶数顺序

调整数组使奇数全部都位于偶数前面。 题目&#xff1a; 输入一个整数数组&#xff0c;实现一个函数&#xff0c;来调整该数组中数字的顺序使得数组中所有的奇数位于数组的前半部分&#xff0c;所有偶数位于数组的后半部分。 思路&#xff1a; 1. 给定两个下标left和right&#…...

日志的规范

确定日志级别&#xff1a; 确保你的系统有一个明确的日志级别策略。通常&#xff0c;日志级别包括DEBUG&#xff0c;INFO&#xff0c;WARN&#xff0c;ERROR和FATAL。DEBUG级别的日志记录所有详细信息&#xff0c;适用于开发和调试环境。INFO级别的日志记录常规操作信息&#x…...

Spring AOP(AOP概念,组成成分,实现,原理)

目录 1. 什么是Spring AOP&#xff1f; 2. 为什么要用AOP&#xff1f; 3. AOP该怎么学习&#xff1f; 3.1 AOP的组成 &#xff08;1&#xff09;切面&#xff08;Aspect&#xff09; &#xff08;2&#xff09;连接点&#xff08;join point&#xff09; &#xff08;3&a…...

Android WebView简单应用:构建内嵌网页浏览功能

在现代移动应用开发中&#xff0c;内嵌网页浏览功能是许多应用程序的常见需求。Android平台提供了WebView组件&#xff0c;它允许开发者将网页内容嵌入到应用中&#xff0c;并提供了丰富的功能和定制选项。本文将介绍如何在Android应用中使用WebView组件&#xff0c;帮助您快速…...

并发——乐观锁常见的两种实现方式,乐观锁的缺点

文章目录 乐观锁常见的两种实现方式1. 版本号机制2. CAS算法 乐观锁的缺点1 ABA 问题2 循环时间长开销大3 只能保证一个共享变量的原子操作 乐观锁常见的两种实现方式 乐观锁一般会使用版本号机制或CAS算法实现。 1. 版本号机制 一般是在数据表中加上一个数据版本号version字段…...

Spring 事务管理

目录 1. 事务管理 1.1. Spring框架的事务支持模型的优势 1.1.1. 全局事务 1.1.2. 本地事务 1.1.3. Spring框架的一致化编程模型 1.2. 了解Spring框架的事务抽象&#xff08;Transaction Abstraction&#xff09; 1.2.1. Hibernate 事务设置 1.3. 用事务同步资源 1.3.1…...

unity修改单个3D物体的重力的大小该怎么处理呢?

在Unity中修改单个3D物体的重力大小可以通过以下步骤实现&#xff1a; 创建一个新的C#脚本来控制重力&#xff1a; 首先&#xff0c;创建一个新的C#脚本&#xff08;例如&#xff1a;GravityModifier.cs&#xff09;并将其附加到需要修改重力的3D物体上。在脚本中&#xff0c…...

[Qt]FrameLessWindow实现调整大小、移动弹窗并具有Aero效果

说明 我们知道QWidget等设置了this->setWindowFlags(Qt::FramelessWindowHint);后无法移动和调整大小&#xff0c;但实际项目中是需要窗口能够调整大小的。所以以实现FrameLess弹窗调整大小及移动弹窗需求&#xff0c;并且在Windows 10上有Aero效果。 先看一下效果&#xf…...

【API生命周期看护】API日落

一、基本概念 在API的整个生命周期中&#xff0c;不可能是永远不变的。功能可能有变动、服务也可能有升级迭代&#xff0c;这个时候对外的能力入口&#xff1a;API自然也需要改变。 一般来说&#xff0c;API的变动是不可以引入兼容性问题的&#xff0c;也即不管做什么变动&am…...

PHP 使用ThinkPHP实现电子邮件发送示例

文章目录 首先我们需要设置我们的邮箱客户端授权&#xff0c;获取到授权码找到我们的邮箱设置去账号中找到这一堆服务&#xff0c;找到后开启smtp服务开启服务后管理服务 接下来需要去下载相应的第三方类库(我这里使用的是PHPMailer)在thinkPHP中封装一下邮件服务类实际调用效果…...

Leetcode-每日一题【剑指 Offer 18. 删除链表的节点】

题目 给定单向链表的头指针和一个要删除的节点的值&#xff0c;定义一个函数删除该节点。 返回删除后的链表的头节点。 注意&#xff1a;此题对比原题有改动 示例 1: 输入: head [4,5,1,9], val 5输出: [4,1,9]解释: 给定你链表中值为 5 的第二个节点&#xff0c;那么在调…...

[LINUX使用] top 命令的使用

COLUMNS150 LINES100 top 序号 是否为启动命令 命令模板 详解 1 no vh 帮助 2 yes -d 0.01 0.01秒的间隔刷新top输出 3 no c COMMAND列切换 4 yes -e [k | m | g | t | p] 以何种计量单位显示内存列 k-kb&#xff0c;m-mb&#xff0c;g-gb&#xff0c;t-t…...

通过redis进行缓存分页,通过SCAN扫描进行缓存更新

问题&#xff1a;当我们要添加缓存时&#xff0c;如果我们用了PageHelper时&#xff0c;PageHelper只会对查询语句有效&#xff08;使用到sql的查询&#xff09;&#xff0c;那么如果我们把查询到的数据都添加到缓存时&#xff0c;就会无法进行分页&#xff1b; 此时我们选择将…...