内容
上一次分析了SpringApplication的静态run方法是先实例化自己本身,然后再调用实例方法run。实例自己本身已经在上一节中分析完成,本节就分析实例run方法
public ConfigurableApplicationContext run(String... args) {
//开启并启动计时器
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
//初始化异常报告期集合
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
//设置headless属性值到系统中
configureHeadlessProperty();
//获取应用程序的监听器组合对象
SpringApplicationRunListeners listeners = getRunListeners(args);
//监听器发布应用程序开始启动事件
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//准备应用上下文环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//配置忽略的bean信息
configureIgnoreBeanInfo(environment);
//打印banner
Banner printedBanner = printBanner(environment);
//创建容器
context = createApplicationContext();
//获取异常报告器
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//准备容器
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//刷新容器
refreshContext(context);
//刷新容器后处理相关逻辑
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 {
//发布应用程序running事件
listeners.running(context);
}
catch (Throwable ex) {
//处理运行异常,主要是通过异常报告器,解析
//运行时产生的异常,然后解析成容易阅读和
//方便排查问题的文本,然后打印
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
这个方法执行完,springboot应用程序就执行完成了。当然里面逻辑是很复杂的,不可能是看起来这几行代码这么简单。
首先从宏观整体解释一下这个方法都干了哪些事情,然后逐步进入里面分析。
这里面和主流程密切相关的步骤有以下一些步骤:
1、获得监听器
2、准备应用上下文环境
3、创建和准备容器
4、刷新容器
5、回调容器启动完成后的执行器
后面的章节,我主要对这些步骤进行详细分析。
本节主要分析获得监听器,进入到方法:SpringApplicationRunListeners listeners = getRunListeners(args);
中:
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
这个代码是不是很熟悉?
其实就是上节中分析过的从spring.factories文件中获取实现了某一个接口的所有类并实例化后返回实例集合。这里我就不展开分析了。
可能有些同学会有疑问,上一节不是有setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
这个步骤吗,这里的为啥不从上面设置的那个集合中直接拿呢?
其实这里获取的是所有的SpringApplicationRunListener,而上一节中获取的是ApplicationListener,是两个不同的东东。
SpringApplicationRunListeners对象是SpringApplicationRunListener的组合对象,在实例化SpringApplicationRunListeners的时候会把获取到的所有SpringApplicationRunListener对象传入到SpringApplicationRunListeners对象的属性里面。
SpringApplicationRunListeners(Log log,
Collection<? extends SpringApplicationRunListener> listeners) {
this.log = log;
this.listeners = new ArrayList<>(listeners);
}
这个属性listeners就是所有的SpringApplicationRunListener。
在我们的系统中所有的spring.factories文件中就只有一个SpringApplicationRunListener的实现类,那就是EventPublishingRunListener。
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
这个就是EventPublishingRunListener的构造参数,通反射实例化EventPublishingRunListener的时候就是调用的这个构造函数,执行构造方法的时候初始化了一个initialMulticaster,还把所有的SpringApplication对象里面的所有ApplicationListener对象都注入到了initialMulticaster这个广播器里面。
所以容器在每次发布事件的时候只需要调组合对象SpringApplicationRunListeners的对应方法,进而调用到里面的所有的SpringApplicationRunListener的对应方法,这里只有一个SpringApplicationRunListener就是EventPublishingRunListener;进而调用到所有ApplicationListener的对应方法。
下面我就以容器开始启动这个事件为一个调用链,分析一下:
进入starting方法
请看我用红框框起来的地方,接下来进入到下一个调用链
总结
SpringApplication对象的实例方法run大概做了以下几件事情:
1、获得监听器
2、准备应用上下文环境
3、创建和准备容器
4、刷新容器
5、回调容器启动完成后的执行器
本节主要解析了获取监听器,监听器是一个组合对象,各个监听器之间的关联关系也进行了分析,大概就是SpringApplicationRunListeners里面包含了多个SpringApplicationRunListener,每个SpringApplicationRunListener里面包含了多个ApplicationListener和一个广播器,用于广播事件。