SpringBoot 启动流程

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);
}

创建默认的应用参数类

Source 继承自 SimpleCommandLinePropertySource,用于解析简单的命令行参数

public DefaultApplicationArguments(String... args) {
    Assert.notNull(args, "Args must not be null");
    this.source = new Source(args);
    this.args = args;
}

准备 Spring 应用环境

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
                                                   DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
    // Create and configure the environment
    // 创建或者获取应用环境
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    // 配置应用环境
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    ConfigurationPropertySources.attach(environment);
    // listeners 环境准备,广播 ApplicationEnvironmentPreparedEvent
    listeners.environmentPrepared(bootstrapContext, environment);
    // 附加配置源
    DefaultPropertiesPropertySource.moveToEnd(environment);
    // 配置其他激活文件
    configureAdditionalProfiles(environment);
    // 将环境绑定给当前应用程序
    bindToSpringApplication(environment);
    if (!this.isCustomEnvironment) {
        environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
    }
    // 配置 propertySource 对它自己的递归依赖
    ConfigurationPropertySources.attach(environment);
    return environment;
}

创建 banner 打印类并执行

打印 banner 的详细操作过程

private Banner printBanner(ConfigurableEnvironment environment) {
    if (this.bannerMode == Banner.Mode.OFF) {
        return null;
    }
    ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
        : new DefaultResourceLoader(null);
    SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
    if (this.bannerMode == Mode.LOG) {
        return bannerPrinter.print(environment, this.mainApplicationClass, logger);
    }
    return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}

创建应用上下文

根据不同的应用类型初始化不同的山下文应用类

protected ConfigurableApplicationContext createApplicationContext() {
    return this.applicationContextFactory.create(this.webApplicationType);
}

准备应用上下文

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
    // 设置应用上下文的 environment
    context.setEnvironment(environment);
    // 应用山下文的后置处理
    postProcessApplicationContext(context);
    // 为上下文应用所有初始化器,执行前面设置的 ApplicationContextInitializer 类
    applyInitializers(context);
    // 触发所有 SpringApplicationRunListener 监听器的 contextPrepared 事件方法。添加所有的事件监听器
    listeners.contextPrepared(context);
    bootstrapContext.close(context);
    // 记录启动日志
    if (this.logStartupInfo) {
        logStartupInfo(context.getParent() == null);
        logStartupProfileInfo(context);
    }
    // Add boot specific singleton beans
    // 注册启动参数bean,将容器指定的参数封装成bean,注入容器
    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    if (printedBanner != null) {
        beanFactory.registerSingleton("springBootBanner", printedBanner);
    }
    if (beanFactory instanceof DefaultListableBeanFactory) {
        ((DefaultListableBeanFactory) beanFactory)
        .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    }
    if (this.lazyInitialization) {
        context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
    }
    // Load the sources
    // 加载所有资源
    Set<Object> sources = getAllSources();
    Assert.notEmpty(sources, "Sources must not be empty");
    // 将 bean 加载到上下文中
    load(context, sources.toArray(new Object[0]));
	// 触发所有 SpringApplicationRunListener 监听器的 contextLoaded 事件方法
    listeners.contextLoaded(context);
}
protected void load(ApplicationContext context, Object[] sources) {
    if (logger.isDebugEnabled()) {
        logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
    }
    BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
    if (this.beanNameGenerator != null) {
        loader.setBeanNameGenerator(this.beanNameGenerator);
    }
    if (this.resourceLoader != null) {
        loader.setResourceLoader(this.resourceLoader);
    }
    if (this.environment != null) {
        loader.setEnvironment(this.environment);
    }
    loader.load();
}

// 后续会使用其将主资源加载到上下文中去,供后续解析使用
BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
    Assert.notNull(registry, "Registry must not be null");
    Assert.notEmpty(sources, "Sources must not be empty");
    this.sources = sources;
    this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
    this.xmlReader = (XML_ENABLED ? new XmlBeanDefinitionReader(registry) : null);
    this.groovyReader = (isGroovyPresent() ? new GroovyBeanDefinitionReader(registry) : null);
    this.scanner = new ClassPathBeanDefinitionScanner(registry);
    this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
}
void load() {
    for (Object source : this.sources) {
        load(source);
    }
}

private void load(Object source) {
    Assert.notNull(source, "Source must not be null");
    if (source instanceof Class<?>) {
        // Class 的方式加载
        load((Class<?>) source);
        return;
    }
    if (source instanceof Resource) {
        // Resource 资源的方式加载
        load((Resource) source);
        return;
    }
    if (source instanceof Package) {
        load((Package) source);
        return;
    }
    if (source instanceof CharSequence) {
        load((CharSequence) source);
        return;
    }
    throw new IllegalArgumentException("Invalid source type " + source.getClass());
}

private void load(Class<?> source) {
    if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
        // Any GroovyLoaders added in beans{} DSL can contribute beans here
        GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
        ((GroovyBeanDefinitionReader) this.groovyReader).beans(loader.getBeans());
    }
    if (isEligible(source)) {
        // 将符合条件的类注册到应用上下文
        this.annotatedReader.register(source);
    }
}

// 不是常规的闭包并且不是匿名类,即可
private boolean isEligible(Class<?> type) {
    return !(type.isAnonymousClass() || isGroovyClosure(type) || hasNoConstructors(type));
}

刷新应用上下文

最终会调用到 AbstractApplicationContext 抽象类中的 refresh() 方法中去

refreshContext(context);

刷新后应用上下文调用

空方法,用于扩展

执行所有的 Runner 运行器

执行所有 Runner 执行器,执行所有 ApplicationRunner 和 CommandLineRunner 两种运行器。

private void callRunners(ApplicationContext context, ApplicationArguments args) {
    List<Object> runners = new ArrayList<>();
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    AnnotationAwareOrderComparator.sort(runners);
    for (Object runner : new LinkedHashSet<>(runners)) {
        if (runner instanceof ApplicationRunner) {
            callRunner((ApplicationRunner) runner, args);
        }
        if (runner instanceof CommandLineRunner) {
            callRunner((CommandLineRunner) runner, args);
        }
    }
}