上一节:【springboot源码解读系列】(一、springboot创建SpringApplication实例,定制SpringApplication)讲到了创建SpringApplication实例时,springboot做的一些事情:设置基础资源、推断应用程序的环境、通过SpringFactories加载我们自定义的初始化器和监听器、推断主入口类。
创建完实例之后,调用了run方法开始运行。
在实际开始工作之前需要做一些准备工作,就像我们上班一样,在开始写代码之前,需要做一些比如打开电脑,编辑器,抽支烟等一系列准备工作,那么springboot也同样如此。
/**
* 运行spring运行程序,创建并且刷新一个新的上下文环境:ApplicationContext
* 应用程序参数(通常从Java主方法传递)
*/
public ConfigurableApplicationContext run(String... args) {
// 创建一个简单的秒表实例(其实并不简单)
StopWatch stopWatch = new StopWatch();
// 开始计时,内部使用的是System.nanoTime(),纳秒级别的
stopWatch.start();
// 声明一个上下文实例:context,并且复制为null
ConfigurableApplicationContext context = null;
// 创建一个SpringBootExceptionReporter集合。他是用于定制异常报告的,
// 简单点来说,我们可以对抛出的异常进行定制化输入,
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 设置无头属性:java.awt.headless,
// 该应用程序,即使没有检测到显示器,也允许其启动.
// 对于服务器来说,是不需要显示器的,所以要这样设置.
configureHeadlessProperty();
// 获取所有的spring应用启动监听器,同样也是通过SpringFactoriesLoader获取的监听器
// 并将其方式SpringApplicationRunListeners中的listeners属性中,他是使用final修饰的,
// 在调用SpringApplicationRunListeners构造函数的时候赋值的。赋值之后不能修改
SpringApplicationRunListeners listeners = getRunListeners(args);
// 调用所有监听器的starting方法,通知各个监听器,spring开始启动了。要干事情的准备开干了
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
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);
}
// 调用监听器的started方法,告知上下文已经刷新,应用程序已经启动
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
// 调用自定义的run实现 这是在springboot上下文刷新程序启动完成之后
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
一来首先他就弄一个定时器出来并且按下开始按钮,开始计时 --> 检车当前的系统是否有显示器,并将其设置为没有显示器也可以启动 --> 通过SpringFactoriesLoader获取所有的自定义监听器 --> 通知所有的监听器,程序正在启动中。
到后面就是大戏了。
其实这里说到的系统启动监听器,初始化器的扩展,这是思路挺值得我们开发中学习的,定义一个接口,定义需要的方法,获取所有的实现类,并且创建其实例,然后在某个节点去调用其方法。将需要的参数进行传递过去,扩展性很好。
一个相信努力就会有结果的程序员,以兴趣驱动技术! ------ CoderOu