SpringBoot启动流程源码分析( 九 )

复制
ServletWebServerApplicationContext#onRefresh方法protected void onRefresh() {super.onRefresh();try {this.createWebServer();} catch (Throwable var2) {throw new ApplicationContextException("Unable to start web server", var2);}}复制
ServletWebServerApplicationContext#createWebServer方法private void createWebServer() {WebServer webServer = this.webServer;ServletContext servletContext = this.getServletContext();if (webServer == null && servletContext == null) {ServletWebServerFactory factory = this.getWebServerFactory();this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});} else if (servletContext != null) {try {this.getSelfInitializer().onStartup(servletContext);} catch (ServletException var4) {throw new ApplicationContextException("Cannot initialize servlet context", var4);}}this.initPropertySources();}复制
Spring容器启动后运行任务SpringApplication#callRunners方法private void callRunners(ApplicationContext context, ApplicationArguments args) {List<Object> runners = new ArrayList();// 通过应用上下文获取所有ApplicationRunner接口实现类的bean集合runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());// 通过应用上下文获取所有CommandLineRunner接口实现类的bean集合runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());AnnotationAwareOrderComparator.sort(runners);Iterator var4 = (new LinkedHashSet(runners)).iterator();// 遍历执行ApplicationRunner实现类和CommandLineRunner实现类中的run方法while(var4.hasNext()) {Object runner = var4.next();if (runner instanceof ApplicationRunner) {this.callRunner((ApplicationRunner)runner, args);}if (runner instanceof CommandLineRunner) {this.callRunner((CommandLineRunner)runner, args);}}private void callRunner(ApplicationRunner runner, ApplicationArguments args) {try {runner.run(args);} catch (Exception var4) {throw new IllegalStateException("Failed to execute ApplicationRunner", var4);}}private void callRunner(CommandLineRunner runner, ApplicationArguments args) {try {runner.run(args.getSourceArgs());} catch (Exception var4) {throw new IllegalStateException("Failed to execute CommandLineRunner", var4);}}复制
处理启动异常最后我们来看看SprignBoot应用程序启动发生异常时调用的方法
SpringApplication#handleRunFailure方法 private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception, Collection<SpringBootExceptionReporter> exceptionReporters, SpringApplicationRunListeners listeners) {try {try {// 处理程序退出编码this.handleExitCode(context, exception);if (listeners != null) {// 应用启动监听器发布启动失败事件listeners.failed(context, exception);}} finally {// 报告异常this.reportFailure(exceptionReporters, exception);if (context != null) {// 关闭Spring IOC容器context.close();}}} catch (Exception var9) {logger.warn("Unable to close ApplicationContext", var9);}// 调用反射工具类抛出运行时异常ReflectionUtils.rethrowRuntimeException(exception);}复制
小结可以看到SpringBoot项目启动过程的源码的源码还是非常复杂的 , 但是在难啃的骨头只要坚持下去还是能啃下它的 。通过分析SpringBoot项目启动过程的源码分析 , 我们可以总结出SpringBoot项目启动过程主要做了以下几件事情:
一、 实例化和初始化SpringApplication对象实例 , 在这个过程会去初始化SpringApplication对象的属性 , 包括:

  • 1.设置是够注册关停钩子标识
  • 2.推断Web应用程序类型
  • 3.加载META-INF/spring.factories配置文件中配置的初始化器和启动监听器
  • 4.推断项目主启动类等工作
二、 运行SpringApplication实例对象的run方法 , 该方法返回的是一个AnnotationConfig在这个过程中又可以分解为以下几个步骤

经验总结扩展阅读