SpringBoot启动流程
整个启动流程包含,推断 WEB 应用类型,设置初始化器,设置 ApplicationListener 监听器,获取并启动 SpringApplicationRunListener 类,准备 Spring 环境,创建并执行 banner 打印类,创建应用上下文,准备应用上下文,刷新应用上下文,刷新应用上下文之后的调用,执行所有的 Runner 运行器。
Spring Boot 的入口程序 @SpringBootApplication public class MainApplication { public static void main(String[] args) { SpringApplication.run(MainApplication.class, args); } } 创建 SpringApplication 对象初始化主要加载资源类到集合中
推断当前 WEB 应用类型(NONE、SERVLET、REACTIVE)
设置应用上下文初始化器
设置 ApplicationListener 监听器
推断主入口应用类
// 创建一个新的实例,这个应用上下文将从指定的来源加载 Bean 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)); // 推断当前 WEB 应用类型,NONE、SERVLET、REACTIVE this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 加载引导程序(2.4.0增加的功能) this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class)); // 设置初始化器 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 设置监听器 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 推断主入口应用类 this.mainApplicationClass = deduceMainApplicationClass(); } run 方法启动创建引导上下文
获取并启动所有 SpringApplicationRunListener 对象
创建默认的应用参数类
准备 Spring 应用环境
创建并执行 banner 打印类
创建应用上下文
准备应用上下文
刷新应用上下文
public ConfigurableApplicationContext run(String... args) { // 创建并启动计时监控类 StopWatch stopWatch = new StopWatch(); stopWatch.start(); // 创建引导上下文 DefaultBootstrapContext bootstrapContext = createBootstrapContext(); ConfigurableApplicationContext context = null; // 设置系统属性“java.awt.headless”的值,默认为 true configureHeadlessProperty(); // 创建所有 Spring 运行监听器并发布应用启动事件, SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(bootstrapContext, this.mainApplicationClass); try { // 初始化默认应用参数类 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 根据运行监听器、引导上下文、应用参数来准备 Spring 环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); // 将要忽略的 bean 参数打开 configureIgnoreBeanInfo(environment); // 创建并执行 banner 打印类 Banner printedBanner = printBanner(environment); // 创建应用上下文 context = createApplicationContext(); // 设置应用程序启动 步骤 context.setApplicationStartup(this.applicationStartup); // 准备应用上下文 prepareContext(bootstrapContext, 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); // 执行所有的 Runner 运行器 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; } 创建引导上下文创建并启动引导上下文,2.4.0 之后的版本增加的新功能
private DefaultBootstrapContext createBootstrapContext() { DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext(); this.bootstrappers.forEach((initializer) -> initializer.intitialize(bootstrapContext)); return bootstrapContext; } 获取所有 SpringApplicationRunListener 对象并启动 // 从 META-INF/spring.factories 中获取所有的配置类,并将其封装到 SpringApplicationRunListeners 对象中去,主要创建的对象为 EventPublishingRunListener private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup); } 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); } } void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) { doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext), (step) -> { if (mainApplicationClass != null) { step.tag("mainApplicationClass", mainApplicationClass.getName()); } }); } // 广播事件 public void starting(ConfigurableBootstrapContext bootstrapContext) { this.initialMulticaster .multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args)); } // applicationStartingEvent 是 SpringBoot 框架最早执行的监听器,在该监听器执行 started 方法时,会继续发布事件,主要是基于 Spring 的事件机制 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); } } } // 返回与给定事件匹配的监听器 protected Collection<ApplicationListener<?>> getApplicationListeners( ApplicationEvent event, ResolvableType eventType) { Object source = event.getSource(); Class<?> sourceType = (source != null ? source.getClass() : null); ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType); // Potential new retriever to populate CachedListenerRetriever newRetriever = null; // Quick check for existing entry on ConcurrentHashMap CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey); if (existingRetriever == null) { // Caching a new ListenerRetriever if possible if (this.beanClassLoader == null || (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) { newRetriever = new CachedListenerRetriever(); existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever); if (existingRetriever != null) { newRetriever = null; // no need to populate it in retrieveApplicationListeners } } } if (existingRetriever != null) { Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners(); if (result != null) { return result; } // If result is null, the existing retriever is not fully populated yet by another thread. // Proceed like caching wasn't possible for this current local attempt. } return retrieveApplicationListeners(eventType, sourceType, newRetriever); } 创建默认的应用参数类