浅析SpringBoot启动类的SpringApplication
SpringApplication是springboot驱动spring应用上下文的引导类,他的run()方法启动Spring应用,实质上是为Spring应用创建并初始化Spring上下文。
执行流程
- 初始化监听器,以及添加到SpringApplication的自定义监听器。
- 发布ApplicationStartedEvent事件,如果想监听ApplicationStartedEvent事件,你可以这样定义:public class ApplicationStartedListener implements ApplicationListener,然后通过SpringApplication.addListener(..)添加进去即可。
- 装配参数和环境,确定是web环境还是非web环境。
- 装配完环境后,就触发ApplicationEnvironmentPreparedEvent事件。
- 如果SpringApplication的showBanner属性被设置为true,则打印启动的Banner。
- 创建ApplicationContext,会根据是否是web环境,来决定创建什么类型的ApplicationContext。
- 装配Context的环境变量,注册Initializers、beanNameGenerator等。
- 发布ApplicationPreparedEvent事件。
- 注册springApplicationArguments、springBootBanner,加载资源等
- 遍历调用所有SpringApplicationRunListener的contextLoaded()方法。
- 调用ApplicationContext的refresh()方法,装配context beanfactory等非常重要的核心组件。
- 查找当前ApplicationContext中是否注册有CommandLineRunner,如果有,则遍历执行它们。
- 发布ApplicationReadyEvent事件,启动完毕,表示服务已经可以开始正常提供服务了。通常我们这里会监听这个事件来打印一些监控性质的日志,表示应用正常启动了。
SpringBoot会触发其他的一些事件,这些事件按下列顺序触发:
(1)ApplicationStartingEvent:项目刚启动时触发,此时除了注册监听器和初始器之外,其他所有处理都没有开始;
(2)ApplicationEnvironmentPreparedEvent:上下文得到环境信息之后触发,此时上下文创建还没有创建;
(3)ApplicationPreparedEvent:bean的定义信息加载完成之后触发,此时bean还没有初始化;
(4)ApplicationReadyEvent:在所有bean初始化完毕,所有回调处理完成,系统准备处理服务请求时触发;
(5)ApplicationFailedEvent:启动过程出现异常时候触发。
SpringApplication.run()
如果我们使用的是SpringApplication的静态run方法,那么,这个方法里面首先要创建一个SpringApplication对象实例,然后调用这个创建好的SpringApplication的实例方法。在SpringApplication实例初始化的时候,它会提前做几件事情:
-
根据classpath里面是否存在某个特征类(org.springframework.web.context.ConfigurableWebApplicationContext)来决定是否应该创建一个为Web应用使用的ApplicationContext类型。
-
使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationContextInitializer。
-
使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationListener。
-
推断并设置main方法的定义类。
它会执行以下步骤:
- 创建一个合适的ApplicationContext实例 (取决于classpath)。
- 注册一个CommandLinePropertySource,以便将命令行参数作为Spring properties。
- 刷新application context,加载所有单例beans。
- 激活所有CommandLineRunner beans。
Run启动方式
@SpringBootApplication
public class Application {
//方式一
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
//方式二
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MySpringConfiguration.class);
app.run(args);
}
//方式三
public static void main(String[] args) {
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.run(args);
}
}
- SpringApplication.run()的底层其实就是new了一个SpringApplication的对象,并执行run()方法。
- 有时我们需要创建多层次的ApplicationContext (例如,父子关系的Spring的ApplicationContext 和SpringMVC),这时我们可以使用SpringApplicationBuilder讲多个方法调用串起来,通过parent() 和 child()来创建多层次的ApplicationContext。
启动信息
启动信息如下:
第 9 行,启动SampleController。
第10行,查找active profile,无,设为default。
第11行,刷新上下文。
第12行,初始化tomcat,设置端口8080,设置访问方式为http。
第13行,启动tomcat服务。
第14行,启动Servlet引擎。
第15行,Spring内嵌的WebApplicationContext 初始化开始。
第16行,Spring内嵌的WebApplicationContext 初始化完成。
第17行,映射servlet,将 dispatcherServlet 映射到 [/] 。
第18行,映射filter,将 characterEncodingFilter 映射到 [/] 。
第19行,映射filter,将 hiddenHttpMethodFilter 映射到 [/] 。
第20行,映射filter,将 httpPutFormContentFilter 映射到 [/] 。
第21行,映射filter,将 requestContextFilter 映射到 [/] 。
第22行,查找 @ControllerAdvice。
第23行,映射路径 "{[/]}" 到 cn.larry.spring.controller.SampleController.home()。
第24行,映射路径 "{[/error]}" 到 org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)。
第25行,映射路径 "{[/error],produces=[text/html]}" 到 org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)。
第30行,tomcat启动完毕。
第31行,SampleController启动耗费的时间。
第32行,初始化 dispatcherServlet 。
第33行,dispatcherServlet 的初始化已启动。
第34行,dispatcherServlet 的初始化已完成。
第35行,收到shutdown关闭请求。
第36行,关闭AnnotationConfigEmbeddedWebApplicationContext。
SpringBootApplication的启动过程非常复杂,只需要在main方法里调用SpringApplicatio.run()方法即可启动Spring Boot应用。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!