目录
上篇分析完启动类注解和SpringApplication构造函数。
SpringApplication::run
启动一个spring应用,创建并刷新一个新的ApplicationContext
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
// 一
stopWatch.start();
// 二
ConfigurableApplicationContext context = null;
// 三
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 四
configureHeadlessProperty();
// 五
SpringApplicationRunListeners listeners = getRunListeners(args);
// 六
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);
}
// 十六
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;
}
一
是一个计时器工具类,这里先记录了项目的启动时间
二
初始化应用上下文
三
初始化异常报告器
四
设置java.awt.headless为true
为true的话是告知系统不要指望显示器、鼠标、键盘等可以正常运行,这是一个服务端程序,用到这些外设的时候需要靠自己模拟
五
我们点进来看
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
我们又看到了getSpringFactoriesInstances这个方法(不记得的可以返回SpringBoot流程解析(一)去回顾),它把SpringApplicationRunListener作为key,取到的value是org.springframework.boot.context.event.EventPublishingRunListener(从spring.factories取得)。最后放入集合返回。
六
点进去
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
先看initialMulticaster
在初始化EventPublishingRunListener时初始化了initialMulticaster
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); } }
再看new ApplicationStartingEvent(this.application, this.args)
构建了一个ApplicationStartingEvent
public EventObject(Object source) { if (source == null) throw new IllegalArgumentException("null source"); this.source = source; }
最后看multicastEvent
先根据事件类型获取到合适的监听器,然后对这些合适的监听器遍历,每一个监听器都开启一个独立的线程去执行监听
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); Executor executor = getTaskExecutor(); for (ApplicationListener<?> listener : getApplicationListeners(event, type)) { if (executor != null) { executor.execute(() -> invokeListener(listener, event)); } else { invokeListener(listener, event); } } }
七
解析启动入参
八
解析配置环境,如配置文件、系统变量等并通过监听器广播环境变量准备完毕事件
九
默认设置spring.beaninfo.ignore
系统属性为true。
保证某些bean不会添加到准备的环境中。
十
打印banner
十一
根据webApplicationType初始化spring上下文
十二
初始化配置的异常报告类
十三
准备上下文
主要分为6个步骤。
- setEnvironment:设置上下文环境
- postProcessApplicationContext:上下文后置处理,默认没做什么事。
- applyInitializers:调用之前实例化的几个ApplicationContextInitializer类的initialize方法
- contextPrepared:向listeners发送上下文已准备完毕的通知。
- load:BeanDefinitionLoader可以加载各种bean,比如注解、XML、package等多种类型的bean,在后面利用BeanDefinitionLoader将这些beans都加载进上下文中。
- contextLoaded:向listeners发送上下文已加载完毕的通知。
十四
刷新上下文(属于spring知识)
十五
空实现,自己可以自定义实现
十六
发布启动完成事件
十七
如果有ApplicationRunner或者CommandLineRunner类型的bean,则触发run函数,启动任务。
十八
监听应用上下文运行