Springboot 启动分析
1 @SpringBootApplication
2 public class Application {
3 public static void main(String[] args) {
4 SpringApplication.run(Application.class, args);
5 }
6 }

public ConfigurableApplicationContext run(String... args) {
// 任务执行计时监听器
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 设置系统java.awt.headless属性,确定是否开启headless模式(默认开启headless模式)
configureHeadlessProperty();
// SpringApplication run方法的监听器,通过 SpringFactoriesLoader 加载
SpringApplicationRunListeners listeners = getRunListeners(args);
// 启动监听器
listeners.starting();
try {
// 创建 SpringBoot 默认启动参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 用于设置活动和默认配置文件以及操作基础属性源的工具,即配置启动环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 配置对不存在的BeanInfo类的重复 ClassLoader 访问
configureIgnoreBeanInfo(environment);
// 打印LOGO
Banner printedBanner = printBanner(environment);
// 创建合适的 ApplicationContext
context = createApplicationContext();
// SpringBoot 启动错误的回调接口,通过 SpringFactoriesLoader 加载
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 准备 Spring 上下文
// 在这个方法中,主要完成了以下几件事:
// 1、设置SpringBoot的环境配置(Environment)
// 2、注册Spring Bean名称的序列化器BeanNameGenerator,并设置资源加载器ResourceLoader
// 3、加载ApplicationContextInitializer初始化器,并进行初始化
// 4、统一将上面的Environment、BeanNameGenerator、ResourceLoader使用默认的Bean注册器进行注册
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 注册销毁上下文的钩子
// 刷新 Spring 上下文
refreshContext(context);
// 刷新后处理
afterRefresh(context, applicationArguments);
// 停止计时监听器
stopWatch.stop();
if (this.logStartupInfo) {
// 打印计时器日志
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
// 上下文已刷新且应用程序已启动
listeners.started(context);
// 运行 ApplicationRunner 和 CommandLineRunner 的实现类
// 二者区别在于入参不同
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
// 发布事件以指示应用程序已准备好上下文环境为请求提供服务
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备此上下文以进行刷新。
prepareRefresh(); // 解析所有 Spring 配置文件,
// 将所有 Spring 配置文件中的 bean 定义封装成 BeanDefinition,
// 加载到 BeanFactory 中
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 配置 beanFactory 的标准上下文特征,
// 例如上下文的 ClassLoader、后置处理器等
prepareBeanFactory(beanFactory); try {
// 允许在上下文子类中对 BeanFactory 进行后续处理,
// 默认实现为空,留给子类实现。
postProcessBeanFactory(beanFactory); // 实例化和调用所有 BeanFactoryPostProcessor
// BeanFactoryPostProcessor 接口是 Spring 初始化 BeanFactory 时对外暴露的扩展点,
// Spring IoC 容器允许 BeanFactoryPostProcessor 在容器实例化任何 bean 之前读取 bean 的定义,并可以修改它。
invokeBeanFactoryPostProcessors(beanFactory); // 注册拦截 BeanPostProcessor,
// 将所有实现了 BeanPostProcessor 接口的类加载到 BeanFactory 中。
// BeanFactoryPostProcessor 是针对 BeanFactory 的扩展,
// 主要用在 bean 实例化之前,读取 bean 的定义,并可以修改它。
registerBeanPostProcessors(beanFactory); // 初始化此上下文的消息源。
initMessageSource(); // 为此上下文初始化应用的事件广播器 ApplicationEventMulticaster
initApplicationEventMulticaster(); // 初始化特定上下文子类中的其他特殊bean ,默认实现为空。
onRefresh(); // 检查监听器bean并注册它们。
registerListeners(); // 实例化所有剩余的(非懒加载)单例。
finishBeanFactoryInitialization(beanFactory); // 最后一步:发布相应的事件。
// 完成此上下文的刷新,主要是推送上下文刷新完毕事件(ContextRefreshedEvent )到监听器。
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
} // 销毁已创建的单例以避免闲置资源(清理不被引用的 Bean)。
destroyBeans(); // 重置“active”标志。
cancelRefresh(ex); // 将异常传播到调用方。
throw ex;
} finally {
// 重置Spring核心中的常见内省缓存,因为我们
// 可能不再需要单例bean的元数据了。。。
resetCommonCaches();
}
}
}
protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
}
public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) {
Assert.notNull(factoryType, "'factoryType' must not be null");
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
// 加载配置文件 META-INF/spring.factories,获取自动配置的类路径,即加载 Resource 资源
List<String> factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse);
if (logger.isTraceEnabled()) {
logger.trace("Loaded [" + factoryType.getName() + "] names: " + factoryImplementationNames);
}
List<T> result = new ArrayList<>(factoryImplementationNames.size());
for (String factoryImplementationName : factoryImplementationNames) {
// 通过反射初始化 Bean factory
result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));
}
AnnotationAwareOrderComparator.sort(result);
return result;
}
Springboot 启动分析的更多相关文章
- SpringBoot无废话入门02:SpringBoot启动分析
1.核心注解 在上文中,我们讲到了@SpringBootApplication是SpringBoot的核心注解. 可以很方便的在idea中下载源码来查看该注解的源码,如下: 可以看到,该注解本身又被其 ...
- SpringBoot启动原理分析
用了差不多两年的SpringBoot了,可以说对SpringBoot已经很熟了,但是仔细一想SpringBoot的启动流程,还是让自己有点懵逼,不得不说是自己工作和学习的失误,所以以此文对Spring ...
- SpringBoot启动流程分析(五):SpringBoot自动装配原理实现
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- SpringBoot启动流程分析(六):IoC容器依赖注入
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- SpringBoot启动流程分析(一):SpringApplication类初始化过程
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- SpringBoot启动流程分析(二):SpringApplication的run方法
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- SpringBoot启动流程分析(三):SpringApplication的run方法之prepareContext()方法
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- SpringBoot启动流程分析(四):IoC容器的初始化过程
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- 深度好文,springboot启动原理详细分析
我们开发任何一个Spring Boot项目,都会用到如下的启动类 1 @SpringBootApplication 2 public class Application { 3 public stat ...
随机推荐
- [原创]配置php+nginx 时遇到的”file not found","access denied"奇怪问题的解决过程
在centos 7中按照我的随笔转载文章"[转载]CentOS 下安装LEMP服务(Nginx.MariaDB/MySQL和PHP)"安装好后,结果无法显示phpinfo()信息, ...
- CF1375F-Integer Game【交互】
正题 题目链接:https://www.luogu.com.cn/problem/CF1375F 题目大意 给出\(a,b,c\).先手每次指定一个数\(k\),然后后手指定一个数字加上\(k\),若 ...
- 使用 Vue 脚手架,为什么要学 webpack?
先问大家一个很简单的问题: vue init webpack prjectName 与 vue create projectName 有什么区别呢? 它们是 Vue-cli 2 和 Vue-cli3 ...
- 巧用优先队列:重载运算符在STL优先队列中的应用
前言 写优先队列优化dijkstra的时候,需要放进优先队列的常常有数值和编号两类,以下介绍让编号捆绑数值放入优先队列的几种方法. 由于过程比较简单,记住代码即可,下面不再讲解,只附上代码,请读者自行 ...
- 苹果的最新MacbookPro,炸到你了么?
一 苹果秋季发布会如期而至.我不是一个标准的果粉.但是我今年用上了macbook pro m1,最期待的就是新款的搭载了M1X的Macbook. 苹果官方也放出了要炸翻全场的宣传语... 这次发布会围 ...
- Spark RDD编程(博客索引,日常更新)
本篇主要是记录自己在中解决RDD编程性能问题中查阅的论文博客,为我认为写的不错的建立索引方便查阅,我的总结会另立他篇 1)通过分区(Partitioning)提高spark性能https://blog ...
- [no_code][Beta]事后分析
设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们要解决的目前的手写表单的电子化问题,办公电子化问题的一个key问题.定义十分清楚: 输入: 手写表单 ...
- [对对子队]会议记录4.20(Scrum Meeting11)
今天已完成的工作 何瑞 工作内容:搭建第三关,添加了运行指令标识 相关issue:搭建关卡2.3 相关签入:4.20签入1 4.20签入2 吴昭邦 工作内容:搭建第三关 相关iss ...
- 阿里Nacos部署
Nacos的部署 一.单机部署 **4.修改 Nacos 存储为 Mysql** 二.集群部署 1.机器部署列表 2.修改 `nacos/conf/application.properties`中的端 ...
- mongodb的索引操作
在mongodb中,当我们一个集合中的数据量非常大时,比如几百万条数据,如果不使用索引,对数据的查询就会进行全表扫描,这个时候查询的速度就会非常的慢,此时我们就需要为集合建立上索引,从而加快查询的速度 ...