系列文章目录
1.Springboot2启动过程源码分析-SpringApplication初始化
2.Springboot2启动过程源码分析-SpringApplication#run
3.Springboot2启动过程源码分析-prepareContext方法
4.Springboot2启动过程源码分析-refresh方法
5.Springboot2启动过程源码分析-Bean的实例化
6.Springboot2启动过程源码分析-总结
前言
上一节对SpringApplication实例化的过程进行了分析,在实例化后就会调用SpringApplication的run方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
本节来看下SpringApplication的run方法都做了什么
SpringApplication#run
以下为run方法的源码及添加的注释
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//1.获取SpringApplicationRunListeners对象
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//2.构造上下文环境对象StandardServletEnvironment
//在prepareEnvironment中会获取到Profile,系统配置application.properties的信息
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
//3.初始化上下文,实例化AnnotationConfigServletWebServerApplicationContext对象
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//4.刷新上下文前的准备阶段
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//5.刷新上下文,包含bean的创建
refreshContext(context);
//6.刷新上下文后的阶段
//目前afterRefresh方法体是空的,可能是预留的方法或者是给大家自行扩展用的
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
//7. 启动监听器
listeners.started(context);
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;
}
1. getRunListeners -> 获取监听器
new SpringApplicationRunListeners的实例
2. prepareEnvironment -> 构造上下文的环境(包括加载指定的profile,加载对应的配置文件)
3. createApplicationContext -> 初始化上下文
createApplicationContext方法内部会通过BeanUtils的instantiateClass反射获取AnnotationConfigServletWebServerApplicationContext实例。在调用AnnotationConfigServletWebServerApplicationContext默认的构造函数时,会实例化两个重要的类:
public AnnotationConfigServletWebServerApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
AnnotatedBeanDefinitionReader: 注解Bean读取器,用于读取和解析bean定义
ClassPathBeanDefinitionScanner: 扫描basePackages定路径下@Component的类极其派生类
4. prepareContext -> 刷新上下文前的准备阶段
这个方法后面会专门有一节进行详细的介绍
5.refreshContext -> 刷新上下文,包含bean的创建 ,webServer创建(如内嵌的tomcat创建启动)
调用AbstractApplicationContext#refresh,也会专门有一节进行介绍
6. afterRefresh -> 刷新上下文后的阶段
方法体是空的
7. listeners.started -> 启动监听器
发布ApplicationStartedEvent事件监听器
总结
以上就是对SpringApplication的run方法主要流程的分析。
这里每一块源码拿出来都可以拓展出很多内容,也应用了很多经典的设计模式。