Skip to content

SpringBoot启动流程深度解析 ​

深入分析SpringBoot应用的启动过程,理解从main方法到应用就绪的完整流程,掌握SpringApplication的工作原理和设计思想。

📋 启动流程概览 ​

SpringBoot应用的启动过程可以分为以下几个关键阶段:

🎯 一、SpringApplication初始化 ​

1.1 构造方法分析 ​

SpringApplication的构造方法是启动流程的入口,让我们看看它的实现:

java
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    this.bootstrapRegistryInitializers = new ArrayList<>(
            getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = deduceMainApplicationClass();
}

关键步骤分析:

  1. primarySources设置:保存主配置类(通常是启动类)
  2. 推断应用类型:WebApplicationType.deduceFromClasspath() 推断应用类型
    • SERVLET:传统Web应用
    • REACTIVE:响应式Web应用
    • NONE:非Web应用
  3. 加载初始化器:从 spring.factories 加载 ApplicationContextInitializer
  4. 加载监听器:从 spring.factories 加载 ApplicationListener
  5. 推断主类:通过堆栈信息推断main方法所在的类

1.2 应用类型推断 ​

java
static WebApplicationType deduceFromClasspath() {
    if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", 
            null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", 
            null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", 
            null)) {
        return WebApplicationType.REACTIVE;
    }
    for (String className : SERVLET_INDICATOR_CLASSES) {
        if (!ClassUtils.isPresent(className, null)) {
            return WebApplicationType.NONE;
        }
    }
    return WebApplicationType.SERVLET;
}

推断逻辑:

1.3 加载初始化器和监听器 ​

从spring.factories加载:

java
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    return getSpringFactoriesInstances(type, new Class<?>[] {});
}

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, 
        Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = getClassLoader();
    Set<String> names = new LinkedHashSet<>(
            SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes, 
            classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

加载过程:

  1. 读取spring.factories:从类路径下的 META-INF/spring.factories 读取配置
  2. 实例化:通过反射创建实例
  3. 排序:按照 @Order 注解或 Ordered 接口排序

🎯 二、run方法执行流程 ​

2.1 run方法签名 ​

java
public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    ConfigurableApplicationContext context = null;
    configureHeadlessProperty();
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting(bootstrapContext, this.mainApplicationClass);
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, 
                applicationArguments);
        configureIgnoreBeanInfo(environment);
        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);
        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.2 关键步骤详解 ​

步骤1:创建BootstrapContext

java
private DefaultBootstrapContext createBootstrapContext() {
    DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
    this.bootstrapRegistryInitializers.forEach((initializer) -> 
            initializer.initialize(bootstrapContext));
    return bootstrapContext;
}

BootstrapContext用于在ApplicationContext创建之前进行一些初始化工作。

步骤2:准备环境(prepareEnvironment)

java
private ConfigurableEnvironment prepareEnvironment(
        SpringApplicationRunListeners listeners,
        DefaultBootstrapContext bootstrapContext,
        ApplicationArguments applicationArguments) {
    
    // 创建或获取环境
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    
    // 配置环境属性源
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    
    // 发布环境准备事件
    ConfigurationPropertySources.attach(environment);
    listeners.environmentPrepared(bootstrapContext, environment);
    
    // 将默认属性源移动到末尾
    DefaultPropertiesPropertySource.moveToEnd(environment);
    
    // 绑定到SpringApplication
    bindToSpringApplication(environment);
    
    if (!this.isCustomEnvironment) {
        environment = new EnvironmentConverter(getClassLoader())
                .convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
    }
    
    ConfigurationPropertySources.attach(environment);
    return environment;
}

环境准备流程图:

步骤3:创建ApplicationContext

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

ApplicationContextFactory DEFAULT = (webApplicationType) -> {
    try {
        switch (webApplicationType) {
        case SERVLET:
            return new AnnotationConfigServletWebServerApplicationContext();
        case REACTIVE:
            return new AnnotationConfigReactiveWebServerApplicationContext();
        default:
            return new AnnotationConfigApplicationContext();
        }
    }
    catch (Exception ex) {
        throw new IllegalStateException("Unable create a default ApplicationContext", ex);
    }
};

根据应用类型创建不同的ApplicationContext:

  • SERVLET:AnnotationConfigServletWebServerApplicationContext
  • REACTIVE:AnnotationConfigReactiveWebServerApplicationContext
  • NONE:AnnotationConfigApplicationContext

步骤4:准备上下文(prepareContext)

java
private void prepareContext(DefaultBootstrapContext bootstrapContext,
        ConfigurableApplicationContext context,
        ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments, Banner printedBanner) {
    
    // 设置环境
    context.setEnvironment(environment);
    
    // 应用上下文后置处理
    postProcessApplicationContext(context);
    
    // 应用上下文初始化器
    applyInitializers(context);
    
    // 发布上下文准备事件
    listeners.contextPrepared(context);
    
    // 记录启动信息
    if (this.logStartupInfo) {
        logStartupInfo(context.getParent() == null);
        logStartupProfileInfo(context);
    }
    
    // 添加单例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());
    }
    
    // 加载源(主配置类)
    Set<Object> sources = getAllSources();
    Assert.notEmpty(sources, "Sources must not be empty");
    load(context, sources.toArray(new Object[0]));
    
    // 发布上下文加载事件
    listeners.contextLoaded(context);
}

准备上下文的关键操作:

  1. 设置环境:将准备好的Environment设置到Context
  2. 应用初始化器:执行 ApplicationContextInitializer
  3. 注册单例Bean:注册 ApplicationArguments、Banner 等
  4. 加载源:加载主配置类(启动类)

步骤5:刷新上下文(refreshContext)

java
private void refreshContext(ConfigurableApplicationContext context) {
    if (this.registerShutdownHook) {
        shutdownHook.registerApplicationContext(context);
    }
    refresh(context);
}

protected void refresh(ApplicationContext applicationContext) {
    Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
    ((AbstractApplicationContext) applicationContext).refresh();
}

刷新上下文实际上是调用 AbstractApplicationContext.refresh() 方法,这是Spring框架的核心方法。

refresh方法的完整流程:

关键子流程解析:

invokeBeanFactoryPostProcessors(处理BeanFactory后置处理器):

这是自动配置的关键步骤,让我们详细分析:

java
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, 
            getBeanFactoryPostProcessors());
    
    // ...
}
java
public static void invokeBeanFactoryPostProcessors(
        ConfigurableListableBeanFactory beanFactory, 
        List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    
    // 先处理BeanDefinitionRegistryPostProcessor
    Set<String> processedBeans = new HashSet<>();
    
    // 1. 处理PriorityOrdered类型的
    // 2. 处理Ordered类型的
    // 3. 处理其他的
    // ...
    
    // 再处理BeanFactoryPostProcessor
    // ...
}

在这个步骤中:

  • 处理 @Configuration 类
  • 处理 @Import 注解
  • 处理自动配置类:这是自动配置生效的关键

finishBeanFactoryInitialization(完成Bean工厂初始化):

java
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // 初始化ConversionService
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
            beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
        beanFactory.setConversionService(
                beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    }
    
    // 注册默认的嵌入式值解析器
    if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(strVal -> 
                getEnvironment().resolvePlaceholders(strVal));
    }
    
    // 初始化LoadTimeWeaverAware Bean
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(
            LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName);
    }
    
    // 停止使用临时类加载器进行类型匹配
    beanFactory.setTempClassLoader(null);
    
    // 允许缓存所有Bean定义元数据
    beanFactory.freezeConfiguration();
    
    // 实例化所有剩余的单例Bean
    beanFactory.preInstantiateSingletons();
}

preInstantiateSingletons(预实例化单例Bean):

java
public void preInstantiateSingletons() throws BeansException {
    // ...
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
    
    for (String beanName : beanNames) {
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (isFactoryBean(beanName)) {
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                // ...
            } else {
                getBean(beanName);
            }
        }
    }
    // ...
}

🎯 三、事件发布机制 ​

3.1 启动事件体系 ​

SpringBoot在启动过程中发布一系列事件,让我们了解这些事件:

事件发布时机:

  1. ApplicationStartingEvent:listeners.starting() - 启动开始
  2. ApplicationEnvironmentPreparedEvent:listeners.environmentPrepared() - 环境准备完成
  3. ApplicationContextInitializedEvent:listeners.contextPrepared() - 上下文初始化完成
  4. ApplicationPreparedEvent:listeners.contextLoaded() - 上下文加载完成
  5. ContextRefreshedEvent:refreshContext() - 上下文刷新完成
  6. ApplicationStartedEvent:listeners.started() - 应用启动完成
  7. ApplicationReadyEvent:listeners.running() - 应用就绪

3.2 事件监听器实现 ​

监听器注册:

java
public class MyApplicationListener implements ApplicationListener<ApplicationReadyEvent> {
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        System.out.println("应用已就绪!");
    }
}

通过注解方式:

java
@Component
public class MyApplicationListener {
    @EventListener
    public void onApplicationReady(ApplicationReadyEvent event) {
        System.out.println("应用已就绪!");
    }
}

🎯 四、Bean加载过程 ​

4.1 Bean定义加载 ​

自动配置类的加载:

java
// AutoConfigurationImportSelector.selectImports
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    }
    AutoConfigurationEntry autoConfigurationEntry = 
            getAutoConfigurationEntry(annotationMetadata);
    return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

protected AutoConfigurationEntry getAutoConfigurationEntry(
        AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    configurations = removeDuplicates(configurations);
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    configurations = getConfigurationClassFilter().filter(configurations);
    fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationEntry(configurations, exclusions);
}

4.2 Bean实例化流程 ​

Bean实例化步骤:

🎯 五、Web服务器启动 ​

5.1 Servlet Web服务器启动 ​

对于Servlet类型的应用,SpringBoot会启动嵌入式Web服务器:

java
// ServletWebServerApplicationContext.onRefresh
@Override
protected void onRefresh() {
    super.onRefresh();
    try {
        createWebServer();
    }
    catch (Throwable ex) {
        throw new ApplicationContextException("Unable to start web server", ex);
    }
}

private void createWebServer() {
    WebServer webServer = this.webServer;
    ServletContext servletContext = getServletContext();
    if (webServer == null && servletContext == null) {
        ServletWebServerFactory factory = getWebServerFactory();
        this.webServer = factory.getWebServer(getSelfInitializer());
    }
    else if (servletContext != null) {
        try {
            getSelfInitializer().onStartup(servletContext);
        }
        catch (ServletException ex) {
            throw new ApplicationContextException("Cannot initialize servlet context", ex);
        }
    }
    initPropertySources();
}

Tomcat服务器启动:

java
// TomcatServletWebServerFactory.getWebServer
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
    if (this.disableMBeanRegistry) {
        Registry.disableRegistry();
    }
    Tomcat tomcat = new Tomcat();
    File baseDir = (this.baseDirectory != null) ? this.baseDirectory 
            : createTempDir("tomcat");
    tomcat.setBaseDir(baseDir.getAbsolutePath());
    Connector connector = new Connector(this.protocol);
    connector.setThrowOnFailure(true);
    tomcat.getService().addConnector(connector);
    customizeConnector(connector);
    tomcat.setConnector(connector);
    tomcat.getHost().setAutoDeploy(false);
    configureEngine(tomcat.getEngine());
    for (Connector additionalConnector : this.additionalTomcatConnectors) {
        tomcat.getService().addConnector(additionalConnector);
    }
    prepareContext(tomcat.getHost(), initializers);
    return getTomcatWebServer(tomcat);
}

🎯 六、启动流程完整时序图 ​

📋 关键源码位置 ​

核心类 ​

类名作用包路径
SpringApplication启动入口org.springframework.boot
ApplicationContext应用上下文org.springframework.context
AbstractApplicationContext上下文抽象实现org.springframework.context.support
ConfigurableApplicationContext可配置的上下文接口org.springframework.context
BeanFactoryBean工厂org.springframework.beans.factory

关键方法 ​

  • SpringApplication.run():启动入口方法
  • SpringApplication.prepareEnvironment():准备环境
  • SpringApplication.createApplicationContext():创建上下文
  • SpringApplication.prepareContext():准备上下文
  • AbstractApplicationContext.refresh():刷新上下文(核心方法)

📋 调试技巧 ​

1. 断点设置 ​

关键断点位置:

java
// 1. 启动入口
SpringApplication.run(MyApplication.class, args);

// 2. 环境准备
prepareEnvironment(...)

// 3. 上下文创建
createApplicationContext()

// 4. 上下文刷新
AbstractApplicationContext.refresh()

// 5. Bean定义处理
invokeBeanFactoryPostProcessors(...)

// 6. Bean实例化
finishBeanFactoryInitialization(...)

2. 日志配置 ​

开启调试日志:

yaml
# application.yml
logging:
  level:
    org.springframework.boot: DEBUG
    org.springframework.context: DEBUG
    org.springframework.beans.factory: DEBUG

📖 学习资源 ​

视频教程 ​

书籍推荐 ​

  • 《Spring Boot实战》 - 汪云飞
  • 《Spring Boot 2精髓》 - 李家智
  • 《深入理解Spring Boot》 - 张卫滨
  • 《Spring源码深度解析》 - 郝佳

网站资源 ​

✅ 学习检查清单 ​

  • [ ] 已理解SpringApplication的初始化过程
  • [ ] 已理解应用类型推断机制
  • [ ] 已理解环境准备流程
  • [ ] 已理解ApplicationContext的创建过程
  • [ ] 已理解上下文刷新流程
  • [ ] 已理解Bean定义加载过程
  • [ ] 已理解Bean实例化流程
  • [ ] 已理解事件发布机制
  • [ ] 已理解Web服务器启动过程
  • [ ] 已绘制启动流程时序图

上一章节:SpringBoot源码深度解析概览
下一章节:自动配置原理
返回目录:源码阅读