springboot: Spring Boot 启动流程详解

Spring Boot 的启动流程是一个精心设计的过程,它简化了传统 Spring 应用的配置和部署。下面详细分析整个启动过程。

0. 完整的启动流程图解

启动入口
    ↓
创建 SpringApplication 实例
    ↓ → 推断应用类型
    ↓ → 加载 Initializers
    ↓ → 加载 Listeners
运行 SpringApplication
    ↓ → 启动计时器
    ↓ → 创建引导上下文
    ↓ → 获取运行监听器
    ↓ → 发布启动事件
准备环境
    ↓ → 创建环境对象
    ↓ → 配置环境
    ↓ → 发布环境准备事件
创建应用上下文
    ↓ → 根据类型创建对应上下文
准备上下文
    ↓ → 设置环境
    ↓ → 应用初始化器
    ↓ → 发布上下文事件
    ↓ → 加载 Bean 定义
刷新上下文(核心)
    ↓ → prepareRefresh()
    ↓ → obtainFreshBeanFactory()
    ↓ → prepareBeanFactory()
    ↓ → postProcessBeanFactory()
    ↓ → invokeBeanFactoryPostProcessors()
    ↓ → registerBeanPostProcessors()
    ↓ → initMessageSource()
    ↓ → initApplicationEventMulticaster()
    ↓ → onRefresh() ← 创建 Web 服务器
    ↓ → registerListeners()
    ↓ → finishBeanFactoryInitialization() ← 初始化单例 Bean
    ↓ → finishRefresh()
后置处理
    ↓ → 发布启动完成事件
    ↓ → 执行 Runner 接口
    ↓ → 发布就绪事件
启动完成

1. 启动入口

标准的 Spring Boot 启动类

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

2. 启动流程详细步骤

整体流程图

1. 启动入口 → 2. 创建SpringApplication实例 → 3. 运行SpringApplication
     ↓
4. 准备环境 → 5. 创建应用上下文 → 6. 准备上下文
     ↓
7. 刷新上下文 → 8. 后置处理 → 9. 启动完成

详细步骤分解

步骤1: 创建 SpringApplication 实例
public class SpringApplication {
    public SpringApplication(Class<?>... primarySources) {
        this(null, primarySources);
    }
    
    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.resourceLoader = resourceLoader;
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        this.webApplicationType = deduceWebApplicationType();
        this.bootstrapRegistryInitializers = new ArrayList<>(
            getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = deduceMainApplicationClass();
    }
}

这个阶段主要完成:

  • 推断应用类型(Servlet、Reactive、None)

  • 加载 BootstrapRegistryInitializer

  • 加载 ApplicationContextInitializer

  • 加载 ApplicationListener

  • 推断主应用类

步骤2: 运行 SpringApplication
public ConfigurableApplicationContext run(String... args) {
    // 1. 启动计时器
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    
    // 2. 创建引导上下文
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    
    // 3. 配置 headless 属性
    configureHeadlessProperty();
    
    // 4. 获取运行监听器
    SpringApplicationRunListeners listeners = getRunListeners(args);
    
    // 5. 发布应用启动事件
    listeners.starting(bootstrapContext, this.mainApplicationClass);
    
    try {
        // 6. 准备应用参数
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        
        // 7. 准备环境
        ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
        
        // 8. 配置忽略的 Bean 信息
        configureIgnoreBeanInfo(environment);
        
        // 9. 打印 Banner
        Banner printedBanner = printBanner(environment);
        
        // 10. 创建应用上下文
        context = createApplicationContext();
        
        // 11. 准备上下文
        prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
        
        // 12. 刷新上下文(核心步骤)
        refreshContext(context);
        
        // 13. 后置处理
        afterRefresh(context, applicationArguments);
        
        // 14. 停止计时器
        stopWatch.stop();
        
        // 15. 发布应用启动完成事件
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
        }
        listeners.started(context);
        
        // 16. 调用 ApplicationRunner 和 CommandLineRunner
        callRunners(context, applicationArguments);
        
        // 17. 发布应用运行中事件
        listeners.ready(context, applicationArguments);
    } catch (Throwable ex) {
        handleRunFailure(context, ex, listeners);
        throw new IllegalStateException(ex);
    }
    
    return context;
}

3. 核心步骤详解

3.1 环境准备 (prepareEnvironment)

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
        DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
    
    // 创建环境
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    
    // 配置环境
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    
    // 绑定环境到 SpringApplication
    ConfigurationPropertySources.attach(environment);
    
    // 发布环境准备事件
    listeners.environmentPrepared(bootstrapContext, environment);
    
    return environment;
}

3.2 创建应用上下文 (createApplicationContext)

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

// 根据应用类型创建不同的上下文
// - SERVLET: AnnotationConfigServletWebServerApplicationContext
// - REACTIVE: AnnotationConfigReactiveWebServerApplicationContext  
// - NONE: AnnotationConfigApplicationContext

3.3 准备上下文 (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);
    
    // 注册单例 Bean
    context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments);
    if (printedBanner != null) {
        context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
    }
    
    // 加载 Bean 定义
    load(context, sources.toArray(new Object[0]));
    
    // 发布上下文加载事件
    listeners.contextLoaded(context);
}

3.4 刷新上下文 (refreshContext) - 核心中的核心

private void refreshContext(ConfigurableApplicationContext context) {
    // 委托给 refresh 方法
    refresh(context);
}

protected void refresh(ApplicationContext applicationContext) {
    // 调用 AbstractApplicationContext.refresh()
    applicationContext.refresh();
}

Spring 上下文的刷新过程:

// 在 AbstractApplicationContext 中
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) {
            // 处理异常...
        }
    }
}

3.5 Spring Boot 的 onRefresh() 方法

// 在 ServletWebServerApplicationContext 中
@Override
protected void onRefresh() {
    super.onRefresh();
    try {
        // 创建 Web 服务器
        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) {
        // 获取 WebServerFactory
        ServletWebServerFactory factory = getWebServerFactory();
        
        // 创建 WebServer
        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();
}

4. 自动配置原理

@SpringBootApplication 注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { 
    @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) 
})
public @interface SpringBootApplication {
    // ...
}

自动配置加载过程

// 在 SpringFactoriesLoader 中加载自动配置类
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
    // 从 META-INF/spring.factories 加载配置
    Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
    
    while (urls.hasMoreElements()) {
        URL url = urls.nextElement();
        Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
        
        String factoryClassNames = properties.getProperty(factoryType.getName());
        // 解析并返回配置类列表
    }
}

5. 启动事件机制

启动事件序列

public class ApplicationStartingEvent extends SpringApplicationEvent {
    // 应用启动事件
}

public class ApplicationEnvironmentPreparedEvent extends SpringApplicationEvent {
    // 环境准备完成事件
}

public class ApplicationContextInitializedEvent extends SpringApplicationEvent {
    // 上下文初始化事件
}

public class ApplicationPreparedEvent extends SpringApplicationEvent {
    // 应用准备完成事件
}

public class ApplicationStartedEvent extends SpringApplicationEvent {
    // 应用启动完成事件
}

public class ApplicationReadyEvent extends SpringApplicationEvent {
    // 应用就绪事件
}

public class ApplicationFailedEvent extends SpringApplicationEvent {
    // 应用启动失败事件
}

自定义启动监听器

@Component
public class MyApplicationListener implements ApplicationListener<ApplicationReadyEvent> {
    
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        // 应用启动完成后执行
        System.out.println("应用启动完成,可以开始处理业务逻辑");
    }
}

6. Runner 接口的执行

ApplicationRunner 和 CommandLineRunner

@Component
public class MyApplicationRunner implements ApplicationRunner {
    
    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 在应用启动后执行
        System.out.println("ApplicationRunner 执行");
    }
}

@Component  
public class MyCommandLineRunner implements CommandLineRunner {
    
    @Override
    public void run(String... args) throws Exception {
        // 在应用启动后执行
        System.out.println("CommandLineRunner 执行");
    }
}

总结

Spring Boot 的启动流程是一个精心编排的过程,主要特点:

  1. 简化配置:通过自动配置减少 XML 配置

  2. 嵌入式容器:内置 Tomcat、Jetty 等 Web 服务器

  3. 事件驱动:通过事件机制实现扩展点

  4. 条件化装配:根据条件自动配置 Bean

  5. 健康检查:提供完善的应用健康监控

理解 Spring Boot 的启动流程对于排查启动问题、进行自定义扩展和优化应用性能都非常有帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值