设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间20 现在时间20 缓存数据 和聪明人交流,和靠谱的人恋爱,和进取的人共事,和幽默的人随行。晚安!

和聪明人交流,和靠谱的人恋爱,和进取的人共事,和幽默的人随行。晚安!

查看: 438|回复: 1

Spring Boot从main方法到内嵌Tomcat的全过程(自动化流程)

[复制链接]

  离线 

TA的专栏

  • 打卡等级:热心大叔
  • 打卡总天数:230
  • 打卡月天数:0
  • 打卡总奖励:3470
  • 最近打卡:2025-09-14 01:35:35
等级头衔

等級:晓枫资讯-上等兵

在线时间
0 小时

积分成就
威望
0
贡献
445
主题
395
精华
0
金钱
4754
积分
899
注册时间
2023-1-4
最后登录
2025-9-14

发表于 2025-8-28 07:37:47 | 显示全部楼层 |阅读模式

Spring Boot的启动过程是一个精心设计的自动化流程,下面我将详细阐述从main方法开始到内嵌Tomcat启动的全过程。

1. 入口:main方法

一切始于一个简单的main方法:

  1. @SpringBootApplication
  2. public class MyApplication {
  3. public static void main(String[] args) {
  4. SpringApplication.run(MyApplication.class, args);
  5. }
  6. }
复制代码

2. SpringApplication初始化

  1. SpringApplication.run()
复制代码
方法内部会创建一个SpringApplication实例:

  1. public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
  2. return new SpringApplication(primarySource).run(args);
  3. }
复制代码

2.1 构造阶段

在SpringApplication构造函数中完成以下关键操作:

  • 推断应用类型:判断是Servlet应用(Spring MVC)还是Reactive应用(Spring WebFlux)
  • 加载ApplicationContextInitializer:通过META-INF/spring.factories加载
  • 加载ApplicationListener:同样通过spring.factories机制加载
  • 推断主配置类:通过堆栈分析找到包含main方法的类

3. 运行阶段:run()方法

  1. run()
复制代码
方法是整个启动过程的核心:

  1. public ConfigurableApplicationContext run(String... args) {
  2. // 1. 创建并启动计时器
  3. StopWatch stopWatch = new StopWatch();
  4. stopWatch.start();
  5. // 2. 初始化应用上下文和异常报告器
  6. ConfigurableApplicationContext context = null;
  7. Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
  8. configureHeadlessProperty();
  9. // 3. 获取SpringApplicationRunListeners并启动
  10. SpringApplicationRunListeners listeners = getRunListeners(args);
  11. listeners.starting();
  12. try {
  13. // 4. 准备环境
  14. ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
  15. ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
  16. // 5. 打印Banner
  17. Banner printedBanner = printBanner(environment);
  18. // 6. 创建应用上下文
  19. context = createApplicationContext();
  20. // 7. 准备应用上下文
  21. prepareContext(context, environment, listeners, applicationArguments, printedBanner);
  22. // 8. 刷新应用上下文(关键步骤)
  23. refreshContext(context);
  24. // 9. 刷新后处理
  25. afterRefresh(context, applicationArguments);
  26. // 10. 停止计时器并发布启动完成事件
  27. stopWatch.stop();
  28. if (this.logStartupInfo) {
  29. new StartupInfoLogger(this.mainApplicationClass)
  30. .logStarted(getApplicationLog(), stopWatch);
  31. }
  32. listeners.started(context);
  33. // 11. 执行Runner
  34. callRunners(context, applicationArguments);
  35. }
  36. catch (Throwable ex) {
  37. handleRunFailure(context, ex, exceptionReporters, listeners);
  38. throw new IllegalStateException(ex);
  39. }
  40. try {
  41. listeners.running(context);
  42. }
  43. catch (Throwable ex) {
  44. handleRunFailure(context, ex, exceptionReporters, null);
  45. throw new IllegalStateException(ex);
  46. }
  47. return context;
  48. }
复制代码

4. 创建应用上下文

  1. createApplicationContext()
复制代码
方法根据应用类型创建不同的应用上下文:

  • Servlet环境:创建
    1. AnnotationConfigServletWebServerApplicationContext
    复制代码
  • Reactive环境:创建
    1. AnnotationConfigReactiveWebServerApplicationContext
    复制代码
  • 普通环境:创建
    1. AnnotationConfigApplicationContext
    复制代码

对于Web应用,会创建

  1. AnnotationConfigServletWebServerApplicationContext
复制代码
,它继承自
  1. ServletWebServerApplicationContext
复制代码

5. 准备应用上下文

  1. prepareContext()
复制代码
方法完成以下工作:

  • 将环境绑定到上下文
  • 后置处理上下文
  • 应用所有初始化器
  • 发布ContextPrepared事件
  • 注册主配置类bean定义
  • 发布ContextLoaded事件

6. 刷新应用上下文

  1. refreshContext()
复制代码
最终调用
  1. AbstractApplicationContext.refresh()
复制代码
,这是Spring容器的核心刷新流程:

  1. public void refresh() throws BeansException, IllegalStateException {
  2. synchronized (this.startupShutdownMonitor) {
  3. // 1. 准备刷新
  4. prepareRefresh();
  5. // 2. 获取新的BeanFactory
  6. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  7. // 3. 准备BeanFactory
  8. prepareBeanFactory(beanFactory);
  9. try {
  10. // 4. 后置处理BeanFactory
  11. postProcessBeanFactory(beanFactory);
  12. // 5. 调用BeanFactoryPostProcessor
  13. invokeBeanFactoryPostProcessors(beanFactory);
  14. // 6. 注册BeanPostProcessor
  15. registerBeanPostProcessors(beanFactory);
  16. // 7. 初始化MessageSource
  17. initMessageSource();
  18. // 8. 初始化事件广播器
  19. initApplicationEventMulticaster();
  20. // 9. 初始化特殊bean(由子类实现)
  21. onRefresh();
  22. // 10. 注册监听器
  23. registerListeners();
  24. // 11. 初始化所有非懒加载单例
  25. finishBeanFactoryInitialization(beanFactory);
  26. // 12. 完成刷新
  27. finishRefresh();
  28. }
  29. catch (BeansException ex) {
  30. // 处理异常...
  31. }
  32. }
  33. }
复制代码

7. 内嵌Tomcat启动的关键:onRefresh()

对于Servlet Web应用,

  1. ServletWebServerApplicationContext
复制代码
重写了
  1. onRefresh()
复制代码
方法:

  1. protected void onRefresh() {
  2. super.onRefresh();
  3. try {
  4. createWebServer();
  5. }
  6. catch (Throwable ex) {
  7. throw new ApplicationContextException("Unable to start web server", ex);
  8. }
  9. }
复制代码

  1. createWebServer()
复制代码
是内嵌服务器启动的关键:

  1. private void createWebServer() {
  2. WebServer webServer = this.webServer;
  3. ServletContext servletContext = getServletContext();
  4. if (webServer == null && servletContext == null) {
  5. // 1. 获取WebServer工厂(Tomcat, Jetty或Undertow)
  6. ServletWebServerFactory factory = getWebServerFactory();
  7. // 2. 创建WebServer
  8. this.webServer = factory.getWebServer(getSelfInitializer());
  9. }
  10. else if (servletContext != null) {
  11. try {
  12. getSelfInitializer().onStartup(servletContext);
  13. }
  14. catch (ServletException ex) {
  15. throw new ApplicationContextException("Cannot initialize servlet context", ex);
  16. }
  17. }
  18. initPropertySources();
  19. }
复制代码

8. Tomcat服务器创建过程

以Tomcat为例,

  1. TomcatServletWebServerFactory.getWebServer()
复制代码
方法:

  1. public WebServer getWebServer(ServletContextInitializer... initializers) {
  2. // 1. 创建Tomcat实例
  3. Tomcat tomcat = new Tomcat();
  4. // 2. 配置基础目录
  5. File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
  6. tomcat.setBaseDir(baseDir.getAbsolutePath());
  7. // 3. 配置连接器
  8. Connector connector = new Connector(this.protocol);
  9. connector.setThrowOnFailure(true);
  10. tomcat.getService().addConnector(connector);
  11. customizeConnector(connector);
  12. tomcat.setConnector(connector);
  13. // 4. 配置Host
  14. tomcat.getHost().setAutoDeploy(false);
  15. configureEngine(tomcat.getEngine());
  16. // 5. 准备上下文
  17. prepareContext(tomcat.getHost(), initializers);
  18. // 6. 创建TomcatWebServer并启动
  19. return getTomcatWebServer(tomcat);
  20. }
复制代码

9. 启动Tomcat

  1. TomcatWebServer
复制代码
构造函数中完成Tomcat的启动:

  1. public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
  2. this.tomcat = tomcat;
  3. this.autoStart = autoStart;
  4. initialize();
  5. }
  6. private void initialize() throws WebServerException {
  7. // 启动Tomcat
  8. this.tomcat.start();
  9. // 启动一个守护线程来等待停止命令
  10. startDaemonAwaitThread();
  11. }
复制代码

10. 自动配置的关键

整个过程中,自动配置是通过

  1. @SpringBootApplication
复制代码
注解中的
  1. @EnableAutoConfiguration
复制代码
实现的:

    1. invokeBeanFactoryPostProcessors()
    复制代码
    阶段会处理自动配置
    1. AutoConfigurationImportSelector
    复制代码
    会加载
    1. META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
    复制代码
    文件中的配置类
  • 对于Tomcat,会加载
    1. ServletWebServerFactoryAutoConfiguration
    复制代码
  • 这个配置类通过
    1. @Import
    复制代码
    引入了
    1. EmbeddedTomcat
    复制代码
    等配置

总结流程

  1. 启动main方法
  2. 创建SpringApplication实例
  3. 运行run()方法
  4. 准备环境
  5. 创建应用上下文(AnnotationConfigServletWebServerApplicationContext)
  6. 准备上下文(注册配置类等)
  7. 刷新上下文(核心)
    • 调用onRefresh()
    • 创建内嵌Web服务器(Tomcat)
    • 启动Tomcat
  8. 发布启动完成事件
  9. 执行Runner

到此这篇关于Spring Boot从main方法到内嵌Tomcat的全过程(自动化流程)的文章就介绍到这了,更多相关Spring Boot启动过程内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

  • 打卡等级:无名新人
  • 打卡总天数:2
  • 打卡月天数:0
  • 打卡总奖励:25
  • 最近打卡:2024-08-06 20:58:20
等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
39
积分
8
注册时间
2023-11-6
最后登录
2024-8-6

发表于 2025-9-2 09:11:31 | 显示全部楼层
感谢楼主分享。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表