目录

一、让我们从启动类打断点一点点剖析启动过程

二、创建 SpringApplication

1.new SpringApplication

2.初始化参数

(1)获取bootstrappers:初始启动引导器

(2)获取ApplicationContextInitializer初始化器

(3)获取ApplicationListener 应用监听器

三、运行 SpringApplication

1.进入run方法

(1)创建引导上下文(Context环境)

(2)bootstrapper其实是个接口

(3)获取所有 RunListener(运行监听器)

(4)准备运行时环境

(5)创建IOC容器

(6)准备ApplicationContext IOC容器的基本信息

(7)IOC容器的经典初始化过程

(8)调用所有runners


一、让我们从启动类打断点一点点剖析启动过程

public static void main(String[] args) {SpringApplication.run(WebApplicationCxf.class, args);
}

二、创建 SpringApplication

1.new SpringApplication

// org.springframework.context.ConfigurableApplicationContext
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return new SpringApplication(primarySources).run(args);
}

2.初始化参数

// org.springframework.boot.SpringApplication#SpringApplication(org.springframework.core.io.ResourceLoader, java.lang.Class<?>...)
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;// 资源加载器Assert.notNull(primarySources, "PrimarySources must not be null");// 断言,判断是否有主配置类this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));// 主配置类信息保存起来(标注@SpringBootApplication的)this.webApplicationType = WebApplicationType.deduceFromClasspath();// 判断web应用的类型(判断是响应式还是原生的servlet工程)// bootstrappers:初始启动引导器(List<Bootstrapper>):去spring.factories文件中找 org.springframework.boot.Bootstrapperthis.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));// 找 ApplicationContextInitializer初始化器;去spring.factories找 ApplicationContextInitializer// 存放在List<ApplicationContextInitializer<?>> initializers中,总共7个setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));// 找 ApplicationListener ;应用监听器。去spring.factories找 ApplicationListener// 存放在List<ApplicationListener<?>> listeners中,总共9个setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));// 决定谁是主程序,有main方法的类就是主程序this.mainApplicationClass = deduceMainApplicationClass();
}

(1)获取bootstrappers:初始启动引导器

// org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>, java.lang.Class<?>[], java.lang.Object...)
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {ClassLoader classLoader = getClassLoader();// Use names and ensure unique to protect against duplicates// 去spring.factories文件中找 org.springframework.boot.BootstrapperSet<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);AnnotationAwareOrderComparator.sort(instances);return instances;
}

(2)获取ApplicationContextInitializer初始化器

都是从spring.factories文件中查找 ApplicationContextInitializer,可能不仅局限于一个spring.factories文件

(3)获取ApplicationListener 应用监听器

都是从spring.factories文件中查找ApplicationListener ,可能不仅局限于一个spring.factories文件

三、运行 SpringApplication

1.进入run方法

// org.springframework.context.ConfigurableApplicationContext
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return new SpringApplication(primarySources).run(args);
}
// org.springframework.boot.SpringApplication#run(java.lang.String...)
public ConfigurableApplicationContext run(String... args) {// 应用停止监听器StopWatch stopWatch = new StopWatch();stopWatch.start(); // 记录应用的启动时间// 创建引导上下文(Context环境)createBootstrapContext()DefaultBootstrapContext bootstrapContext = createBootstrapContext();ConfigurableApplicationContext context = null;// 设置headless属性方法(java.awt.headless),让当前应用进入headless模式(自力更生模式,详情自行百度)configureHeadlessProperty();//获取所有 RunListener(运行监听器)【为了方便所有Listener进行事件感知】SpringApplicationRunListeners listeners = getRunListeners(args);// 遍历 SpringApplicationRunListener 调用 starting 方法,相当于通知所有对系统正在启动过程感兴趣的人,项目正在 starting。listeners.starting(bootstrapContext, this.mainApplicationClass);try {// 保存命令行参数;ApplicationArgumentsApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 准备运行时环境ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);configureIgnoreBeanInfo(environment);// 打印bannerBanner printedBanner = printBanner(environment);// 创建IOC容器// 根据项目类型(Servlet)创建容器,当前会创建 AnnotationConfigServletWebServerApplicationContextcontext = createApplicationContext();context.setApplicationStartup(this.applicationStartup);// 准备ApplicationContext IOC容器的基本信息prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);// 刷新IOC容器,调用IOC容器的经典初始化过程,创建容器中的所有组件refreshContext(context);// 容器刷新完成后工作,方法是空的afterRefresh(context, applicationArguments);// 监控花费的时间stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}// 所有监听器 调用 listeners.started(context); 通知所有的监听器 startedlisteners.started(context);// 调用所有runnerscallRunners(context, applicationArguments);}// 如果有异常,调用Listener 的 failed方法catch (Throwable ex) {handleRunFailure(context, ex, listeners);throw new IllegalStateException(ex);}try {// 调用所有监听器的 running 方法 listeners.running(context); 通知所有的监听器 runninglisteners.running(context);}// running如果有问题。继续通知 failed 。调用所有 Listener 的 failed;通知所有的监听器 failedcatch (Throwable ex) {handleRunFailure(context, ex, null);throw new IllegalStateException(ex);}return context;
}

(1)创建引导上下文(Context环境)

private DefaultBootstrapContext createBootstrapContext() {DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext(); // 创建默认的引导上下文// 获取到所有之前的 bootstrappers 挨个执行 intitialize() 来完成对引导启动器上下文环境设置this.bootstrappers.forEach((initializer) -> initializer.intitialize(bootstrapContext));return bootstrapContext;
}

(2)bootstrapper其实是个接口

public interface Bootstrapper {/*** Initialize the given {@link BootstrapRegistry} with any required registrations.* @param registry the registry to initialize*/void intitialize(BootstrapRegistry registry);
}

(3)获取所有 RunListener(运行监听器)

还是去从spring.factories文件中查找SpringApplicationRunListener。

private SpringApplicationRunListeners getRunListeners(String[] args) {Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };return new SpringApplicationRunListeners(logger,getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),this.applicationStartup);
}

找到一个listener:

Listener实际是个接口,有如下方法:

(4)准备运行时环境

// org.springframework.boot.SpringApplication#prepareEnvironment
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {// Create and configure the environment// 返回或者创建基础环境信息对象。StandardServletEnvironmentConfigurableEnvironment environment = getOrCreateEnvironment();// 配置环境信息,通过命令行参数或者配置文件获取配置属性值configureEnvironment(environment, applicationArguments.getSourceArgs());// 绑定环境信息ConfigurationPropertySources.attach(environment);// 所有监听器遍历调用 listener.environmentPrepared();通知所有的监听器当前环境准备完成listeners.environmentPrepared(bootstrapContext, environment);DefaultPropertiesPropertySource.moveToEnd(environment);// 激活额外的环境configureAdditionalProfiles(environment);// 绑定一些值bindToSpringApplication(environment);if (!this.isCustomEnvironment) {environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,deduceEnvironmentClass());}ConfigurationPropertySources.attach(environment);return environment;
}

(5)创建IOC容器

// org.springframework.boot.SpringApplication#createApplicationContext
protected ConfigurableApplicationContext createApplicationContext() {// 根据项目类型(Servlet)创建容器,当前会创建 AnnotationConfigServletWebServerApplicationContextreturn this.applicationContextFactory.create(this.webApplicationType);
}

(6)准备ApplicationContext IOC容器的基本信息

// org.springframework.boot.SpringApplication#prepareContext
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments, Banner printedBanner) {// 保存基础环境信息context.setEnvironment(environment);// IOC容器的后置处理流程(注册一些组件、读取配置文件资源、注册资源加载器、准备类型转换器等等)postProcessApplicationContext(context);// 应用初始化器:applyInitializers// 遍历所有的 ApplicationContextInitializer 。调用 initialize方法。来对ioc容器进行初始化扩展功能applyInitializers(context);// 遍历所有的 listener 调用 contextPrepared方法。listeners.contextPrepared(context);bootstrapContext.close(context);if (this.logStartupInfo) {logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// Add boot specific singleton beansConfigurableListableBeanFactory beanFactory = context.getBeanFactory();beanFactory.registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {beanFactory.registerSingleton("springBootBanner", printedBanner);}if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}if (this.lazyInitialization) {context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());}// Load the sourcesSet<Object> sources = getAllSources();Assert.notEmpty(sources, "Sources must not be empty");load(context, sources.toArray(new Object[0]));// 所有的监听器 调用 contextLoaded。通知所有的监听器 contextLoadedlisteners.contextLoaded(context);
}

(7)IOC容器的经典初始化过程

spring容器创建流程参考博文

spring系列-注解驱动原理及源码-spring容器创建流程-CSDN博客

注意:

spring默认的onRefresh()方法是空的,springboot将onRefresh()方法重写,加入了tomcat的启动。

// org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh
protected void onRefresh() {super.onRefresh();try {// 创建一个web应用createWebServer();}catch (Throwable ex) {throw new ApplicationContextException("Unable to start web server", ex);}
}

springboot嵌入式tomcat启动原理参考博文:

https://blog.csdn.net/A_art_xiang/article/details/122435665

(8)调用所有runners

默认是没有runner。

// org.springframework.boot.SpringApplication#callRunners
private void callRunners(ApplicationContext context, ApplicationArguments args) {List<Object> runners = new ArrayList<>();// 获取容器中的 ApplicationRunnerrunners.addAll(context.getBeansOfType(ApplicationRunner.class).values());// 获取容器中的 CommandLineRunnerrunners.addAll(context.getBeansOfType(CommandLineRunner.class).values());// 合并所有runner并且按照@Order进行排序AnnotationAwareOrderComparator.sort(runners);// 遍历所有的runner。调用 run 方法for (Object runner : new LinkedHashSet<>(runners)) {if (runner instanceof ApplicationRunner) {callRunner((ApplicationRunner) runner, args);}if (runner instanceof CommandLineRunner) {callRunner((CommandLineRunner) runner, args);}}
}

runner是一个接口:

@FunctionalInterface
public interface ApplicationRunner {/*** Callback used to run the bean.* @param args incoming application arguments* @throws Exception on error*/void run(ApplicationArguments args) throws Exception;
}

springboot启动流程,手把手打断点一步步看运行步骤相关推荐

  1. SpringBoot启动流程分析(四):IoC容器的初始化过程

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  2. Java面试--SpringBoot启动流程

    一.SpringBoot是什么 SpringBoot 是依赖于 Spring 的,比起 Spring,除了拥有 Spring 的全部功能以外,SpringBoot 无需繁琐的 Xml 配置,这取决于它 ...

  3. SpringBoot 启动流程(细节拉满)

    SpringBoot 启动流程(细节拉满) 网上搜了一下,这方面网上的资料不少,有些从@SpringBootApplication来入手讲.个人不能苟同吧,讲一讲我的理解.还有一些讲的比较笼统,我来写 ...

  4. SpringBoot启动流程解析

    写在前面: 由于该系统是底层系统,以微服务形式对外暴露dubbo服务,所以本流程中SpringBoot不基于jetty或者tomcat等容器启动方式发布服务,而是以执行程序方式启动来发布(参考下图ke ...

  5. Springboot启动流程分析(四):完成启动流程

    目录 一 添加BeanPostProcessors到IOC容器 二 国际化支持 三 初始化监听器的多路播放器 四 刷新容器 五 注册监听器到IOC容器的多播器 六 完成bean的大规模实例化 6.1 ...

  6. SPRINGBOOT启动流程及其原理

    Spring Boot.Spring MVC 和 Spring 有什么区别? 分别描述各自的特征: Spring 框架就像一个家族,有众多衍生产品例如 boot.security.jpa等等:但他们的 ...

  7. SpringBoot启动流程简要

    SpringBoot启动流程大概: 初始化SpringApplication 根据项目的配置情况和Conditional条件来推断是否是一个Web应用. 读取所有jar包下面spring.factor ...

  8. 高级面试题--SpringBoot启动流程解析

    写在前面: 由于该系统是底层系统,以微服务形式对外暴露dubbo服务,所以本流程中SpringBoot不基于jetty或者tomcat等容器启动方式发布服务,而是以执行程序方式启动来发布(参考下图ke ...

  9. SpringBoot入门到精通-SpringBoot启动流程(七)

    定义自己的starter SpringBoot入门到精通-Spring的注解编程(一) SpringBoot入门到精通-SpringBoot入门(二) SpringBoot入门到精通-Spring的基 ...

最新文章

  1. C#中Path类的常用方法
  2. web.py开发web 第四章 Sqlalchemy(事件监听与初始化)
  3. ArrayList 与 LinkedList 底层实现
  4. 怎么通过media foundation将图像数据写入虚拟摄像头_千倍成本压缩!特斯拉开发虚拟激光雷达,替代最贵自动驾驶传感器...
  5. python 数据科学 包_什么时候应该使用哪个Python数据科学软件包?
  6. java fileinputstream.read(byte[])_Java分享笔记:FileInputStream流的 read()方法 和 read(byte[] b)方法...
  7. java代码ftp重命名未生效_java使用apache commons连接ftp修改ftp文件名失败原因
  8. python excel导入oracle数据库_【Python代替Excel】12:Python操作oracle数据库
  9. 两栈共享存储空间算法
  10. Android 中发送短信
  11. php网站整合ck播放器,CKplayer 整合播放M3U8视频
  12. 读书笔记 之《软件架构设计: 大型网站技术架构与业务架构融合之道》
  13. Android 10.0 Launcher3 抽屉式(双层)app列表排序
  14. 学习机器学习开始的一些别人的看法
  15. 一文读懂数据库的文本数据类型:CHAR,VARCHAR,TEXT,BLOG,NCHAR、NVARCHAR、NTEXT
  16. 物联网|物联网领域常用通信类型
  17. TI飞控出现联系方式,Ti飞控芯片锁了解决办法
  18. 【管理系统中计算机应用】决策支持系统
  19. 进销存ERP系统、销售单、采购单、退货单、库存管理、库存盘点、调拨、借入、借出、出库、入库、归还单、收款单、付款单、资金流水、销售报表、采购报表、库存报表、财务报表、商品库、电商erp、连锁erp 1
  20. QT CREATOR出现no Qt platform plugin问题

热门文章

  1. [转]Linux下的Makefile
  2. pgsql的存储过程调用mysql_PostgreSQL存储过程循环调用方式
  3. 建标库标准怎么导出pdf_保存和导出PDF文档,这款OCR文字识别软件能做到
  4. idea实现抽象类的所有抽象方法_深入理解Java的接口和抽象类
  5. 人工智能论坛_浙江大学人工智能论坛在北京召开
  6. 关于surface安装foxmail附件预览失效解决方案
  7. Linux关闭开关机动画,centos7删除开机动画及修改启动菜单
  8. python入门之函数调用第一关_零基础学习 Python 之与函数的初次相见
  9. python常用编译器和解释器的区别_Python常用编译器原理及特点解析
  10. go语言和java比_去过大场面试后,java程序员有没有必要转学Go语言?