版本说明
Spring Boot:【2.4.6】
Spring: 【5.3.7】
SpringApplication#run方法主流程
项目为一个简单的springboot项目,只导入web模块。
接上文springtboot启动主流程-构造方法,从SpringApplication#run方法开始分析,构造完SpringApplication实例后调用其run方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
run方法是springboot启动过程中另一重要方法,它在springboot和spring之间建立联系
// Run the Spring application, creating and refreshing a new ApplicationContext.
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 创建一个DefaultBootstrapContext,作为参数,调用全部BootstrapRegistryInitializer的initialize方法
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// 配置java.awt.headless,服务端程序无显示器
configureHeadlessProperty();
// 获取所有SpringApplicationRunListeners
SpringApplicationRunListeners listeners = getRunListeners(args);
// 发布ApplicationStartingEvent事件
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 创建一个StandardServletEnvironment并配置环境,发布ApplicationEnvironmentPreparedEvent事件
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);
// 打印banner
Banner printedBanner = printBanner(environment);
// 1. 创建ApplicationContext,通过从上到下实例化,实例化了一个DefaultListableBeanFactory,作为Spring框架中很重要的一个类
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
// 2. 用已有的数据准备环境
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 3. 刷新Context,最终会回到Spring中的核心流程AbstractApplicationContext#refresh
refreshContext(context);
// 4. 目前为空
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
// 发布ApplicationStartedEvent
listeners.started(context);
// 获取ApplicationRunner和CommandLineRunner,并调用其run方法
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
// 发布ApplicationFailedEvent
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
// 发布ApplicationReadyEvent
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
从上面代码可以看出,refreshContext(context)方法回到了Spring框架完成了IOC容器的初始化,bean的实例化,bean初始化等工作。这里先跳过Spring的分析,只分析其余的部分。
发布事件 - 观察者模式的应用
SpringBoot中引入了大量的事件,开发者可以扩展对事件的监听,只关注感兴趣的事件,这样可以降低代码之间的耦合。这里只分析下这两句
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
上面代码获取了SpringApplicationRunListener,然后用SpringApplicationRunListeners来包装,SpringApplicationRunListeners封装了事件的发布工作
void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
(step) -> {
if (mainApplicationClass != null) {
step.tag("mainApplicationClass", mainApplicationClass.getName());
}
});
}
上面方法传入了两个lambda表达式,看下doWithListeners的执行逻辑
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
Consumer<StartupStep> stepAction) {
StartupStep step = this.applicationStartup.start(stepName);
// 遍历所有listener,等同于调用所有listenerAction.accept(listener)
this.listeners.forEach(listenerAction);
if (stepAction != null) {
stepAction.accept(step);
}
step.end();
}
默认下SpringApplicationRunListener接口只有一个实现,就是在spring-boot包下的spring.factories中定义,唯一的实现类就是这个EventPublishingRunListener
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
这个类就是个事件发布器,构造过程中实例化了一个SimpleApplicationEventMulticaster,用来真正去发布事件
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);
}
}
SimpleApplicationEventMulticaster的multicastEvent方法负责遍历所有listener并调用listener
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// 是否允许在单独executor中执行
Executor executor = getTaskExecutor();
// 获取所有已注册的listen
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
run方法发布的事件
JDK中的观察者模式
下面是引自《设计模式之禅》中的观察者模式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XmVyyb6i-1644309778318)(C:\Users\sunhongyue_it\AppData\Roaming\Typora\typora-user-images\image-20220208153459029.png)]
JDK从1.0就定义了Observer接口,Observable类,但是到JDK9就给废弃了,文档写的理由是:
This class and the
Observer
interface have been deprecated. The event model supported byObserver
andObservable
is quite limited, the order of notifications delivered byObservable
is unspecified, and state changes are not in one-for-one correspondence with notifications. For a richer event model, consider using thejava.beans
package. For reliable and ordered messaging among threads, consider using one of the concurrent data structures in thejava.util.concurrent
package. For reactive streams style programming, see theFlow
API
可以参考sof讨论
End
run方法完成的核心内容:
- 运行Spring application,创建并刷新一个新的ApplicationContext(eg.AnnotationConfigServletWebServerApplicationContext)
- context持有一个beanFactory(eg.DefaultListableBeanFactory)