SpringBoot的启动流程分析(2)
我们来分析SpringApplication启动流程中的run()方法,代码如下
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
看起来方法比较长,不过我们主要看启动流程,哪些监控,失败分析的我们以后再说,所以这个方法中关键的几步如下
context = createApplicationContext();
prepareContext(context,environment,listeners,applicationArguments,printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
没错,看到关键的方法就是这4个,我们首先分析 createApplicationContext()方法,代码如下
public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext";
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
+ "annotation.AnnotationConfigApplicationContext"; protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
contextClass = Class.forName(this.webEnvironment
? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}
很明显,在web环境下它加载并创建了 ConfigurableApplicationContext,简单点说就是创建了ApplicationContext,即创建了Bean的容器(BeanFactory)
然后看 prepareContext()方法,可以看出,这个方法是将配置,参数,监听器,以及banner信息注入applicationContext中
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
} // Add boot specific singleton beans
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
} // Load the sources
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
listeners.contextLoaded(context);
}
方法3是启动的关键函数,在这一步中springboot已经启动,因为比较复杂,我们稍后说。所以我么先看 afterRefresh(context, applicationArguments),其细节如下
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
callRunners(context, args);
} private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<Object>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<Object>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
} private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
try {
(runner).run(args.getSourceArgs());
}
catch (Exception ex) {
throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
}
}
看到这里大家想起来什么了没有?没错,我们自己现实的 ApplicationRunner 或 CommandLineRunner 这些类就是在这里被调用执行的。
最后我们来看最重要的 refreshContext(context),其相关的代码如下
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
最后落在了AbstractApplicationContext.refresh方法中。
这个方法的每一步上都有明确的注释。
prepareRefresh()准备刷新,设置应用的开启时间,设置active标志,并执行一些属性的初始化工作。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();获取BeanFactory。
prepareBeanFactory(beanFactory)执行一些BeanFactory的初始化工作。
postProcessBeanFactory(beanFactory)设置BeanFactory的后置处理器。(可以参考Spring中Bean的生命周期)
invokeBeanFactoryPostProcessors(beanFactory)调用BeanFactory的后置处理器。
registerBeanPostProcessors(beanFactory)在容器内的所有Bean实例化之前注册Bean的前(后)置处理器。(可以参考BeanPostProcessor)
initMessageSource()设置messgeSource
initApplicationEventMulticaster()初始化Context的广播器
onRefresh()根据子类的实现方式不同做不同的事。EmbeddedWebApplicationContext会创建内置的Tomcat并启动。
registerListeners()创建监听器
finishBeanFactoryInitialization(beanFactory)实例化BeanFactory中非懒加载的单例的Bean。这个方法比较关键。
finishRefresh()初始化或启动声明周期相关的任务,发布Context已经刷新的消息。
以上是springboot启动的粗略流程,让我们大致明白启动的流程是什么样的。各个步骤解释的不是特别详细,也有可能还有错误。
以后可能会逐步的进行详细的分析。
引出的问题
BeanFactory是什么。
Tomcat中和BeanFactory中生命周期的问题。
Spring中的事件监听机制。
Tomcat和Servlet和Springboot的关联。
SpringBoot的启动流程分析(2)的更多相关文章
- SpringBoot的启动流程分析(1)
通过分析我们可以找到 org.springframework.boot.SpringApplication 中如下, public static ConfigurableApplicationCont ...
- SpringBoot启动流程分析(二):SpringApplication的run方法
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- 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方法之prepareContext()方法
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- SpringBoot启动流程分析(四):IoC容器的初始化过程
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- SpringBoot IoC启动流程、初始化过程及Bean生命周期各个阶段的作用
目录 SpringBoot IoC启动流程.初始化过程及Bean生命周期各个阶段的作用 简述 首先明确IoC容器是啥 准备-SpringApplication的实例化 启动-SpringApplica ...
- SpringBoot的启动流程是怎样的?SpringBoot源码(七)
注:该源码分析对应SpringBoot版本为2.1.0.RELEASE 1 温故而知新 本篇接 SpringBoot内置的各种Starter是怎样构建的? SpringBoot源码(六) 温故而知新, ...
随机推荐
- 《Java算法》贪心算法
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解. 贪心算法的经典案例: 跳跃游戏: 给定一个非负整 ...
- ES6对数组的扩展(简要总结)
文章目录 数组的扩展(ES6) 1. 扩展运算符 2. Array.from 3. Array.of() 4. copyWithin() 5. find() 和 findIndex() 6. fill ...
- CentOS7.2下部署zabbix4.0
整体部署采用centos7+php+apache+mariadb 基础环境配置优化 1. 关闭防火墙 [root@monitor_53 ~]$ systemctl stop firewalld [ro ...
- javascript对url进行编码和解码
这里总结下JavaScript对URL进行编码和解码的三个方法. 为什么要对URL进行编码和解码 只有[0-9[a-Z] $ - _ . + ! * ' ( ) ,]以及某些保留字,才能不经过编码直接 ...
- 添加junit和spring-test还是用不了@Test和@RunWith(SpringJUnit4ClassRunner.class)注解
pom.xml依赖如下 <!-- spring 单元测试组件包 --> <dependency> <groupId>org.springframework</ ...
- 来来来,告诉你一个简单易上手的KPI打分的方子
▋1/3 前言 每个企业都要定期为员工的工作来进行考核,有月度考核.季度考核和年度考核. 这次月度考核,我打算用一种新的方式来执行. 我在我们研发小组内曾分享过能力-意愿四象限图.根据岗位技术能力和工 ...
- Win32 API编程——前言
一丶什么是Win32 API? 微软为了保护操作系统的安全性和稳定性,把系统分为内核层和用户层(内核层的代码只能在当CPU的特权级为R0状态下执行,用户层的代码在CPU特权级为R0和R3都能执行),w ...
- 二分查找(Java)
题目: 编写程序,完成以下功能: (1)输入5个整数到数组中; (2)使用冒泡法对5个数按从小到大排序,输出排序后的数组; (3)输入一个整数X,在数组中用二分法查找X,找到输出X在数组中的下标,找不 ...
- 持续集成(CI):Jmeter+Ant+Jenkins定时构建
这里Jenkins的安装部署以及工程项目的整体配置不做赘述,其它博文已经说明,这里主要是赘述Ant的相关配置,build.xml文件配置以及项目中的部分配置 一.build.xml 在Ant的安装目录 ...
- MongoDB(一):NoSQL简介、MongoDB简介
1. NoSQL简介 1.1 什么是NoSQL NoSQL(NoSQL= Not Only SQL),意即“不仅仅是SQL",是一项全新的数据库理念,泛指非关系型的数据库. 1.2 为什么需 ...