前言【SpringBoot启动流程源码分析】SpringBoot
项目的启动流程是很多面试官面试中高级Java程序员喜欢问的问题 。这个问题的答案涉及到了SpringBoot
工程中的源码 , 也许我们之前看过别的大牛写过的有关SpringBoot
项目启动流程的文章,但是自己没有去研究一遍总是会记忆不深刻 。有句话叫做“纸上来得终觉浅,绝知此事要躬行”,我觉得说得非常在理 。底层的东西 , 也只有自己深入研究过一遍甚至好几遍源码才能彻底搞懂并记忆牢固 。下面笔者来带领大家详细分析SpringBoot
启动过程中到底做了哪些事情 , 把本文仔细看完了,面对面试官问的有关SpringBoot
启动过程做了哪些工作的面试题就迎刃而解了!
启动类入口方法首先我们通过SpringApplication
类的静态Run方法进入SpringBoot
项目的启动入口
/*** @param primarySource springboot启动类* @param args 启动参数*/public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {return run(new Class[]{primarySource}, args);}
复制
从上面的源码中我们可以看到SpringBoot
启动类返回的应用上下文类是ConfigurableApplicationContext
然后我们进入另一个静态run方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return (new SpringApplication(primarySources)).run(args);}
复制
在上面这个静态run方法里面最终会通过SpringApplication
类的构造函数实例化一个SpringApplication
类实例对象,后面在调用SpringApplication
实例对象的run方法
SpringApplication类实例化和初始化接下来我们看看SpringApplication
类在实例化时做了什么事情
public SpringApplication(Class<?>... primarySources) {this((ResourceLoader)null, primarySources);}
复制
可以看到在SpringApplication
类上面这个构造方法里面又调用了另一个构造方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {// 实例化sources属性this.sources = new LinkedHashSet();// 打印模式为控制台打印this.bannerMode = Mode.CONSOLE;// 设置记录启动日志信息标识为truethis.logStartupInfo = true;// 设置添加命令行属性标识为truethis.addCommandLineProperties = true;//设置addConversionService属性为truethis.addConversionService = true;// 设置headless属性为truethis.headless = true;// 设置注册应用关停钩子属性为truethis.registerShutdownHook = true;// 实例化additionalProfiles属性this.additionalProfiles = new HashSet();//默认非自定义环境this.isCustomEnvironment = false;// 上一步传过来的resourceLoader为nullthis.resourceLoader = resourceLoader;// 断言primarySources参数不能为空,也就是springboot应用类不能为空Assert.notNull(primarySources, "PrimarySources must not be null");// 将传递过来的springboot启动类参数转成List后加入LinkedHashSet集合后赋值给primarySources属性this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));// 根据类路径推断web应用类型this.webApplicationType = WebApplicationType.deduceFromClasspath(); this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));// 设置初始化器属性// 设置监听器属性this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));// 推断主启动类this.mainApplicationClass = this.deduceMainApplicationClass();}
复制
从上面的源码中我们分析的结果来看,实例化SpringApplication
类的过程做了以下几件事情:
- 初始化SpringApplication启动类中的大部分属性变量
- 推断web应用类型
- 通过加载类路径目录META-INF下的
spring.factories
文件读取出初始化器和监听器集合并设置到SpringApplication
实例对应的初始化器和监听器属性列表中 - 推断主启动类并赋值给
SpringApplication
启动类的mainApplicationClass
属性
WebApplicationType#deduceFromClasspath
方法private static final String[] SERVLET_INDICATOR_CLASSES = new String[]{"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"};static WebApplicationType deduceFromClasspath() {if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {return REACTIVE;} else {String[] var0 = SERVLET_INDICATOR_CLASSES;int var1 = var0.length;for(int var2 = 0; var2 < var1; ++var2) {String className = var0[var2];if (!ClassUtils.isPresent(className, (ClassLoader)null)) {return NONE;}}return SERVLET;}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 一次SpringBoot版本升级,引发的血案
- SpringBoot 03: 常用web组件 - - - 拦截器 + Servlet + 过滤器
- SpringBoot 02: 初识SpringBoot
- 超详细 SpringBoot 整合 Elasticsearch .md
- SpringBoot 01: JavaConfig + @ImportResource + @PropertyResource
- MindStudio模型训练场景精度比对全流程和结果分析
- 纸嫁衣4第三章交错通关流程图文攻略
- 纸嫁衣4第一章异途通关流程图文攻略-纸嫁衣4红丝缠第一章怎么过
- 纸嫁衣4第二章不期通关流程图文攻略-纸嫁衣4红丝缠第二章怎么过
- 洛克王国初秋落叶活动流程攻略-洛克王国初秋落叶怎么玩