springboot(一)启动流程分析
本文仅此记录阅读springboot2.5.4源码的一些总结分析,并对部分源码做了批注,方便理解springboot的启动流程和spring bean的生命周期
springboot启动分为两个部分,下面我会分别探究
官方文档:docs.spring.io/spring-boot…
我们的springboot项目启动时,通常会包含一个主启动类
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
public class WordApplication {
public static void main(String[] args) {
SpringApplication.run(WordApplication.class, args);
}
}
最终还是调用的内部一个run方法,我们可以主观的把它分为两部分
1 创建 SpringApplication对象
2 执行SpringApplication的run方法
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
// 也可以直接调用这个方法,传入多个主启动类
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
第一部分
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 传入为null
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// 主启动类
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 类型推断(会根据使用的类判断)
// org.springframework.web.servlet.DispatcherServlet(soringmvc核心入口)这个类
// 没设么特殊情况,我们web服务都是返回的 SERVLET 类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 在SpringFactories中寻找并注册注册BootstrapRegistryInitializer(函数式接口)
// 这是个回调接口,会在run方法的createBootstrapContext()方法调用
this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
// 同样这也是在SpringFactories寻找并注册ApplicationContextInitializer
// 官方的介绍是这样
// 用于在刷新之前初始化Spring ConfigurableApplicationContext的回调接口,通常在需要对应用程序上下文进行一些编程初始化的web应用程序中使用
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 在SpringFactories寻找并注册ApplicationListener
// 这是spring提供的事件监听器,方便对整个springboot的流程进行扩展
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断main方法的类
// StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
// 获取栈的信息遍历栈所有方法来获取main方法类
this.mainApplicationClass = deduceMainApplicationClass();
}
下面时springboot默认提供的监听器和初始化回调类
第二部分
public ConfigurableApplicationContext run(String... args) {
// 计时器,记录启动时间等等
StopWatch stopWatch = new StopWatch();
// 开始计时
stopWatch.start();
// 维护了一个上下文环境,用于提供大量参数的管理,也方便统一些事件 的参数
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// 配置 java.awt.headless 进系统参数
// System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
configureHeadlessProperty();
// 获取spirng的监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
// 发布容器启动事件
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 获取args参宿和
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备环境遍历
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 配置忽略BeanInfo
configureIgnoreBeanInfo(environment);
// 打印spring的启动banner
Banner printedBanner = printBanner(environment);
// 根据推断的web类型启动相应的容器
// mvc为AnnotationConfigServletWebServerApplicationContext
// 内嵌了tomcat(重写了容器启动的onRefresh()方法,配置并启动Tomcat对象)
context = createApplicationContext();
// 设置一下容器当前状态
context.setApplicationStartup(this.applicationStartup);
// 准备容器
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 刷新容器(spring容器启动,也是核心)
// 对beanfactory的一系列操作都在里面
refreshContext(context);
// 模板方法,啥都没有,用于子类扩展实现
afterRefresh(context, applicationArguments);
// 停止计时
stopWatch.stop();
// 启动容器启动完成事件
listeners.started(context);
// 虽然启动完成了但是spring还是为我们保留了一点扩展口
// ApplicationRunner和CommandLineRunner的回调
callRunners(context, applicationArguments);
}catch (Throwable ex) {
// 调用启动失败事件
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);}
try {
// 发布 运行中事件
listeners.running(context);
}catch (Throwable ex) {
// 调用启动失败事件
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
下面是对run方法的细节的详细分析
创建引导上下文
createBootstrapContext()
private DefaultBootstrapContext createBootstrapContext() {
// 创建了一个空的DefaultBootstrapContext
DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
// 这里就是上文所说的,会在这回调所有BootstrapRegistryInitializer的initialize方法
// 但是这里spring并没有提供默认BootstrapRegistryInitializer,应该是留给我们程序猿扩展吧
this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
return bootstrapContext;
}
获取监听器
getRunListeners(args)
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
// 获取所有默认提供的SpringApplicationRunListener,即SpringApplication运行方法的侦听器
// 这里是boot提供的
// 这里springboot就提供了一个监听器 EventPublishingRunListener
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
this.applicationStartup);
}
写到这不知道大家有没有晕,这么多listener和listeners
class SpringApplicationRunListeners {
private final Log log;
private final List<SpringApplicationRunListener> listeners;
private final ApplicationStartup applicationStartup;
void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
(step) -> {
if (mainApplicationClass != null) {
step.tag("mainApplicationClass", mainApplicationClass.getName());
}
});
}
......
......
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction) {
doWithListeners(stepName, listenerAction, null);
}
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
Consumer<StartupStep> stepAction) {
StartupStep step = this.applicationStartup.start(stepName);
this.listeners.forEach(listenerAction);
if (stepAction != null) {
stepAction.accept(step);
}
step.end();
}
}
SpringApplicationRunListeners默认的监听器(部分源码)
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
private final SpringApplication application;
private final SimpleApplicationEventMulticaster initialMulticaster;
@Override
public void starting(ConfigurableBootstrapContext bootstrapContext) {
this.initialMulticaster
.multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
}
......
}
默认情况下SpringApplicationRunListeners只有一个监听器EventPublishingRunListener,每次SpringApplicationRunListeners发布一个事件,都回统一调用doWithListeners(), 其实就是调用EventPublishingRunListener的不同的事件方法,而EventPublishingRunListener又分装了一下,所有的事件都会调用内部维护的SimpleApplicationEventMulticaster类的multicastEvent()
@Override
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)) {
// executor 默认为空
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}else {
// 最终是同步执行
invokeListener(listener, event);
}
}
}
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
// 默认也为null
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {doInvokeListener(listener, event);}
catch (Throwable err) {errorHandler.handleError(err);}
}else {
// 出现异常不会拦截
doInvokeListener(listener, event);}
}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
// 调用ApplicationListener监听器的并传入事件
listener.onApplicationEvent(event);
// 如果一个监听器需要监控多个event那就需要对event再次做类型判断
}
catch (ClassCastException ex) {
.......
}
}
ApplicationListener是一个函数式接口,和SpringApplicationRunListener稍有不同的是,和SpringApplicationRunListener把事件作为了参数,让实现者去处理不同的事件(当然参数也必须维护在event中),而ApplicationListener更加细化的把不同事件对应成了不同的方法,想要处理某个事件只需要实现其中的一个方法。
所以如果一个监听器实现了ApplicationListener,但是需要监控多个event事件,那就必须在onApplicationEvent方法中对event做类型判断 以此区分事件。
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
}
总结:这里获取了springboot提供的监听器,每次发布事件,会优先遍历所有实现了SpringApplicationRunListener(springboot提供)接口,然后向所有ApplicationListener(spring提供)发送事件。
springboot为项目启动提供了非常非常丰富的事件,丰富到甚至有点冗余繁琐
public interface SpringApplicationRunListener {
// 启动前
default void starting(ConfigurableBootstrapContext bootstrapContext) { starting();}
@Deprecated
default void starting() {}
// 环境准备完成
default void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
ConfigurableEnvironment environment) {environmentPrepared(environment)}
@Deprecated
default void environmentPrepared(ConfigurableEnvironment environment) {}
// ApplicationContext构建完成时
default void contextPrepared(ConfigurableApplicationContext context) {}
// ApplicationContext完成加载
default void contextLoaded(ConfigurableApplicationContext context) {}
// ApplicationContext刷新并启动后
default void started(ConfigurableApplicationContext context) {}
// callRunners()之后
default void running(ConfigurableApplicationContext context) {}
// ApplicationContext出错时调用
default void failed(ConfigurableApplicationContext context, Throwable exception) {}
}
由于篇幅原因,后面我会对run方法的关键步骤进行分析