SpringBoot源码分析(二)启动原理
Springboot的jar启动方式,是通过IOC容器启动 带动了Web容器的启动
而Springboot的war启动方式,是通过Web容器(如Tomcat)的启动 带动了IOC容器相关的启动
一、不可不说的Web容器(如Tomcat)
不管是jar启动还是war包启动,都绕不开web容器相关。先了解这个怎么工作的,以Tomcat为例,
看看Springboot 怎么来自动装配tomcat 相关的组件?
1.1 相关类
相关包org.springframework.boot.autoconfigure.web,在springboot的自动配置包的web下(自动配置功能都在这个autoconfigure包下)。
embedded(内嵌)里面四个类一个A四B,一个:
EmbeddedWebServerFactoryCustomizerAutoConfiguration(内嵌web容器工厂自定义定制器装配类)
四个具体容器相关:
JettyWebServerFactoryCustomizer、NettyWebServerFactoryCustomizer、TomcatWebServerFactoryCustomizer、UndertowWebServerFactoryCustomizer
一个自动配置类+四个常用web容器定制器
1.2.工作流程
以Tomcat定制器切入,断点落在构造器上,启动。
总结出它的工作流程:
1.启动=》2.createWebServer=》
3.拿TomcatServletWebServerFactory(tomcatWeb容器工厂)=》
4.拿WebServerFactoryCustomizer(工厂定制器)
也就是拿工厂定制器获取工厂,再拿工厂获取web容器,这么个流程
1.3.具体工作
可以仔细看下相关工厂是如何配置创建容器运行的
TomcatServletWebServerFactory的创建Tomcat方法
创建Tocmat类并设置相关这些组件,应该很熟悉(以后出Tomcat源码分析)。
TomcatWebServerFactoryCustomizer的customize定制方法,通过类serverProperties配置文件设置工厂的属性
二、SpringBoot的jar启动方式
来自:
打开源码:
其实两步,一步创建SpringApplication ,一步run运行。
创建类做的事情比较简单,主要包括判断web应用类型、用SpringFactories技术从 spring.factories 文件里获取ApplicationContextInitializer 对应类和ApplicationListener,最后获取当前应用的启动类的类对象。
2.1 run方法
其实大多是准备、工具、事件等,最核心的还是里面的refreshContext(context);带动了IOC容器启动
2.2 refreshContext(context)
其实大部分内容在之前IOC容器源码写过,唯一的区别在于:
SpringIOC的refresh方法里的onRefresh方法是空的,而SpringBoot继承重写了这个方法!
SpringBoot的onRefresh:
SpringBoot里应用上下文是用的新的ServletWebServerApplicationContext类(更具体实现之一是AnnotationConfigServletWebServerApplicationContext)
这里就开始和上面说过的Web容器相关知识衔接上了,这里进行的Web容器(Tomcat)的创建运行!
createWebServer:
这里就是判断有没有Server以及环境,没有的话就获取web容器制造工厂,最后通过工厂获取Tomcat赋值。
实际上获取Tomcat创建的时候,此时构造器最后的代码就是启动,TomcatWebServer类构造器如下:
TomcatWebServer的initialize:
最终在IOC 容器中的 org.springframework.context.support.AbstractApplicationContext的refresh 的
onReFresh方法带动了Tomcat启动
三、SpringBoot的war包启动方式
Springboot的war启动方式,是通过Web容器(如Tomcat)的启动 带动了IOC容器相关的启动
3.1 Tomcat加载war
要说Tomcat怎么加载war包就不得不从servlet3.0的特性说起:
1.web应用启动,会创建当前Web应用导入jar包中的 ServletContainerInitializer类的实例
2.ServletContainerInitializer 类必须放在jar包的 META-INF/services目录下,文件名称为javax.servlet.ServletContainerInitializer
3.文件的内容指向ServletContainerInitializer实现类的全路径
4.ServletContainerInitializer实现类使用@HandlesTypes注解, 在我们应用启动的时候,加载注解指定的的类
3.2 Spring中的ServletContainerInitializer
Spring中实现ServletContainerInitializer的类是SpringServletContainerInitializer
总结:HandlesTypes指定了WebApplicationInitializer类,并在onStartup方法中,创建这些需要加载的类的实例,并且循环调用他们的onStartup方法。
3.2 工作过程
1.Tomcat启动,war包应用的jar包里找ServletContainerInitializer 文件,然后找到spring-web-5.1.2.RELEASE.jar这个jar包里的META-INF\services\javax.servlet.ServletContainerInitializer 文件指向自己实现的SpringServletContainerInitializer并执行它
2.将@HandlesTypes标注的类(WebApplicationInitializer)都传入到 onStartup()的方法中Set<Class<?>>参数中
,通过 ReflectionUtils.accessibleConstructor(waiClass).newInstance());,为这些类创建实例
3.调用WebApplicationInitializer的onStartup方法
4.而Springboot启动类继承了SpringBootServletInitializer(实现了接口WebApplicationInitializer)
5.而我们的启动类StudySpringbootApplication没有重写onStartup,调的SpringBootServletInitializer的onStartup
6.而SpringBootServletInitializer的onStartup方法调了我们重写的configure方法,加载启动。
4.1 实战调试细节
可以把断点打到第六行里builder.sources,通过断点一看调用栈和代码,逻辑就全出来了:
StudySpringbootApplication.configure <<==== 父类SpringBootServletInitializer(主类继继承的这个类).createRootApplicationContext
父类SpringBootServletInitializer.createRootApplicationContext:
注意重点是 调用了自己的方法(传入主类)和 run方法
run源码:
继续打开run源码:
是不是很熟悉,和jar启动的run IOC一样!所以最终还是殊途同归,还是走了application.run()方法,走了IOC容器启动Refresh!
__EOF__

本文链接:https://www.cnblogs.com/chz-blogs/p/12595734.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构