SpringBoot启动过程详解

Spring Boot 的启动过程是一个精心设计的流程,下面我将结合源码详细解释这一过程。

1. 入口点:main 方法和 SpringApplication 初始化

Spring Boot 应用的启动通常从包含 @SpringBootApplication 注解的类的 main 方法开始:

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

SpringApplication 构造过程

SpringApplication.run() 方法内部会创建一个新的 SpringApplication 实例:

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

SpringApplication 的构造函数主要完成以下工作:

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    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. 确定应用类型(WebApplicationType):根据类路径判断是 SERVLET、REACTIVE 还是非 WEB 应用
  2. 加载 BootstrapRegistryInitializer 实例
  3. 加载并初始化 ApplicationContextInitializer
  4. 加载并初始化 ApplicationListener
  5. 推断主应用类

2. run 方法执行流程

run() 方法是 Spring Boot 启动的核心:

public ConfigurableApplicationContext run(String... args) {
    // 1. 创建启动计时器
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    
    // 2. 创建引导上下文
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    
    // 3. 准备环境
    ConfigurableEnvironment environment = prepareEnvironment(bootstrapContext, applicationArguments);
    
    // 4. 打印 banner
    Banner printedBanner = printBanner(environment);
    
    // 5. 创建应用上下文
    context = createApplicationContext();
    
    // 6. 准备应用上下文
    prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
    
    // 7. 刷新上下文
    refreshContext(context);
    
    // 8. 刷新后处理
    afterRefresh(context, applicationArguments);
    
    // 9. 停止计时器
    stopWatch.stop();
    
    // 10. 发布启动完成事件
    listeners.started(context);
    listeners.running(context);
    
    return context;
}

2.1 创建引导上下文 (BootstrapContext)

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

2.2 准备环境 (prepareEnvironment)

private ConfigurableEnvironment prepareEnvironment(DefaultBootstrapContext bootstrapContext,
        SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
    // 创建环境
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    
    // 配置环境
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    
    // 发布环境准备事件
    listeners.environmentPrepared(bootstrapContext, environment);
    
    // 将环境绑定到SpringApplication
    bindToSpringApplication(environment);
    
    // 如果是自定义环境,转换为标准环境
    if (!this.isCustomEnvironment) {
        environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
                deduceEnvironmentClass());
    }
    
    // 配置属性源
    ConfigurationPropertySources.attach(environment);
    return environment;
}

2.3 创建应用上下文 (createApplicationContext)

根据应用类型创建不同的应用上下文:

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 instance, "
                + "you may need a custom ApplicationContextFactory", ex);
    }
};

2.4 准备应用上下文 (prepareContext)

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.registerShutdownHook) {
        shutdownHook.registerApplicationContext(context);
    }
    
    // 将bootstrapContext添加到上下文
    context.getBeanFactory().registerResolvableDependency(
            BootstrapContext.class, bootstrapContext);
    
    // 将printedBanner添加到上下文
    if (printedBanner != null) {
        context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
    }
    
    // 配置bean定义生成器
    if (context instanceof BeanDefinitionRegistry) {
        configureBeanDefinitionRegistry((BeanDefinitionRegistry) context);
    }
    
    // 发布上下文加载事件
    listeners.contextLoaded(context);
}

2.5 刷新上下文 (refreshContext)

这是启动过程中最关键的步骤,调用了 AbstractApplicationContext.refresh() 方法:

protected void refreshContext(ConfigurableApplicationContext context) {
    refresh(context);
    if (this.registerShutdownHook) {
        try {
            context.registerShutdownHook();
        } catch (AccessControlException ex) {
            // Not allowed in some environments.
        }
    }
}

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

AbstractApplicationContext.refresh() 方法的主要步骤:

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 1. 准备刷新上下文
        prepareRefresh();
        
        // 2. 获取新的BeanFactory
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        
        // 3. 准备BeanFactory
        prepareBeanFactory(beanFactory);
        
        try {
            // 4. 后处理BeanFactory
            postProcessBeanFactory(beanFactory);
            
            // 5. 调用BeanFactory后处理器
            invokeBeanFactoryPostProcessors(beanFactory);
            
            // 6. 注册Bean后处理器
            registerBeanPostProcessors(beanFactory);
            
            // 7. 初始化消息源
            initMessageSource();
            
            // 8. 初始化事件广播器
            initApplicationEventMulticaster();
            
            // 9. 初始化特殊bean
            onRefresh();
            
            // 10. 注册监听器
            registerListeners();
            
            // 11. 完成BeanFactory初始化
            finishBeanFactoryInitialization(beanFactory);
            
            // 12. 完成刷新
            finishRefresh();
        } catch (BeansException ex) {
            // 处理异常...
        }
    }
}

Spring Boot 通过 SpringApplication.refreshContext() 方法调用了这个标准 Spring 刷新过程,并添加了一些 Boot 特有的功能。

2.6 自动配置的实现

自动配置的核心是 @EnableAutoConfiguration 注解,它引入了 AutoConfigurationImportSelector

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    // ...
}

AutoConfigurationImportSelector 负责加载 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中定义的自动配置类:

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
        ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader())
                .getCandidates();
        Assert.notEmpty(configurations,
                "No auto configuration classes found in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. "
                        + "If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }
}

2.7 内嵌Web服务器启动

对于Web应用,内嵌服务器是在 onRefresh() 阶段启动的。以Tomcat为例:

// ServletWebServerApplicationContext
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();
}

3. 启动后处理

启动完成后,Spring Boot 会发布一些事件:

// SpringApplication.java
listeners.started(context);
listeners.running(context);

这些事件包括:

  • ApplicationStartedEvent:应用已启动但命令执行器未运行
  • ApplicationReadyEvent:应用已准备好服务请求

4. 总结流程图

Spring Boot 启动过程可以简化为以下流程图:

main()
  └─ SpringApplication.run()
       ├─ 创建 SpringApplication 实例
       │    ├─ 确定应用类型
       │    ├─ 加载 ApplicationContextInitializer
       │    └─ 加载 ApplicationListener
       ├─ 执行 run() 方法
       │    ├─ 准备环境
       │    ├─ 创建应用上下文
       │    ├─ 准备上下文
       │    ├─ 刷新上下文(核心)
       │    │    ├─ 准备刷新
       │    │    ├─ 获取 BeanFactory
       │    │    ├─ 准备 BeanFactory
       │    │    ├─ 执行 BeanFactoryPostProcessor
       │    │    ├─ 注册 BeanPostProcessor
       │    │    ├─ 初始化消息源
       │    │    ├─ 初始化事件广播器
       │    │    ├─ onRefresh()(启动Web服务器)
       │    │    ├─ 注册监听器
       │    │    ├─ 完成Bean初始化
       │    │    └─ 完成刷新
       │    ├─ 刷新后处理
       │    └─ 发布启动完成事件
       └─ 返回应用上下文

整个启动过程充分利用了Spring框架的基础设施,同时通过自动配置、starter机制等简化了开发者的配置工作,实现了约定优于配置的理念。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐