背景
从大学接触Spring 3.0到现在已经有5、6年的时间了,但工作后由于公司有自研的系统,一直没有机会在实际工作中用到。后来听说Spring推出了微服务架构叫做Spring Boot,挺火爆,就尝试着去研究了一段时间。
开始
通过跟踪代码引用,我们可以看到
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
String[] args) {
return new SpringApplication(primarySources).run(args);
}
从代码可以看出,Spring Boot启动第一步会先构建SpringApplication实例,然后调用其run()方法,并传入命令行参数。
- 构建SpringApplication
具体分析参考 构建SpringApplication - SpringApplication.run(String... args)
SpringApplication.run(String... args)方法的具体实现如下,从代码中可以看到,这一过程主要完成了以下工作:
- 启动计时器,用来记录程序启动耗时情况
- 实例化异常报告器,用于对启动过程进行错误分析
- 加载并启动监听器,用于监听ApplicationContext构造过程,并在关键节点完成时,广播对应的事件
- 解析命令行参数,并封装到ApplicationArguments实例中
- 构建容器运行环境
- 打印Banner
- 创建ApplicationContext应用上下文
- 构建ApplicationContext
- 刷新ApplicationContext
public ConfigurableApplicationContext run(String... args) {
// 开始计时
stopWatch.start();
ConfigurableApplicationContext context = null;
// 异常报告器
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// 1. 加载并启动监听器,用于监听ApplicationContext构造过程
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
// 解析命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// 2.构造容器环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
// 设置需要忽略的Bean
configureIgnoreBeanInfo(environment);
// 打印Banner
Banner printedBanner = printBanner(environment);
// 3.创建容器
context = createApplicationContext();
// 4.实例化SpringBootExceptionReporter.class,用来支持报告关于启动的错误
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 5.准备容器
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
// 6.刷新容器
refreshContext(context);
// 7.刷新容器后的扩展接口
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
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;
}
加载并启动监听器
监听器的作用主要是在Spring Boot启动过程中的关键节点(如:开始启动、环境构建完成、启动成功、启动失败等)抛出一个事件对象,并将该事件对象广播给对应的ApplicationListner监听器,由监听器去完成对应的处理逻辑。
详细信息参考:SpringApplicationRunListener
准备Environment
详细信息参考:Spring Boot启动-构造容器环境
创建ApplicationContext
创建ApplicationContext实现代码如下:
- 根据Web应用类型,获取对应的ApplicationContext子类
- 实例化ApplicationContext子类
// 常量定义
public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework.boot."
+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
+ "annotation.AnnotationConfigApplicationContext";
protected ConfigurableApplicationContext createApplicationContext() {
// 1. 根据Web应用类型,获取对应的ApplicationContext子类
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
// 2. 实例化子类
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
BeanFactory也是在此过程中被创建
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
网友评论