springboot2.0.6的运行流程以及怎么执行SpringApplication的run方法

发布时间:2021-09-04 11:13:35 作者:chen
来源:亿速云 阅读:304
# SpringBoot 2.0.6的运行流程以及怎么执行SpringApplication的run方法

## 目录
1. [SpringBoot核心设计思想](#1-springboot核心设计思想)
2. [SpringApplication初始化阶段](#2-springapplication初始化阶段)
3. [run方法执行流程详解](#3-run方法执行流程详解)
   - [3.1 准备环境阶段](#31-准备环境阶段)
   - [3.2 创建应用上下文](#32-创建应用上下文)
   - [3.3 前置处理与Bean定义加载](#33-前置处理与bean定义加载)
   - [3.4 刷新应用上下文](#34-刷新应用上下文)
   - [3.5 后置处理与启动完成](#35-后置处理与启动完成)
4. [关键扩展点分析](#4-关键扩展点分析)
5. [与内嵌容器的整合](#5-与内嵌容器的整合)
6. [总结](#6-总结)

---

## 1. SpringBoot核心设计思想

SpringBoot 2.0.6基于Spring Framework 5.0.10构建,其核心设计思想主要体现在三个方面:

1. **约定优于配置**:通过默认配置和自动装配机制减少XML配置
2. **内嵌容器**:集成Tomcat/Jetty等Servlet容器实现独立运行
3. **启动器(Starter)**:通过依赖管理简化第三方库集成

```java
// 典型启动类示例
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

2. SpringApplication初始化阶段

当调用SpringApplication.run()时,首先会执行构造方法初始化:

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    // 1. 设置主配置源(通常为@SpringBootApplication标注的类)
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    
    // 2. 推断Web应用类型(REACTIVE/SERVLET/NONE)
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    
    // 3. 从META-INF/spring.factories加载ApplicationContextInitializer
    setInitializers((Collection) getSpringFactoriesInstances(
        ApplicationContextInitializer.class));
    
    // 4. 加载ApplicationListener
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    
    // 5. 推断主启动类(通过堆栈分析)
    this.mainApplicationClass = deduceMainApplicationClass();
}

初始化阶段关键点: - 通过spring.factories机制加载扩展组件 - 应用类型推断基于类路径是否存在特定类(如DispatcherHandler) - 主类推断算法会分析调用栈找到包含main方法的类

3. run方法执行流程详解

3.1 准备环境阶段

public ConfigurableApplicationContext run(String... args) {
    // 1. 创建StopWatch监控启动耗时
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    
    // 2. 配置headless模式
    configureHeadlessProperty();
    
    // 3. 获取SpringApplicationRunListeners
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();
    
    try {
        // 4. 准备环境配置
        ConfigurableEnvironment environment = prepareEnvironment(listeners, args);
        configureIgnoreBeanInfo(environment);
        
        // 打印Banner
        Banner printedBanner = printBanner(environment);
        
        // 5. 创建应用上下文(根据webApplicationType)
        context = createApplicationContext();
        
        // 6. 准备异常报告器
        exceptionReporters = getSpringFactoriesInstances(
            SpringBootExceptionReporter.class,
            new Class[] { ConfigurableApplicationContext.class }, context);
        
        // 7. 准备上下文
        prepareContext(context, environment, listeners, printedBanner);
        
        // 8. 刷新上下文(核心阶段)
        refreshContext(context);
        
        // 9. 后置处理
        afterRefresh(context, args);
        stopWatch.stop();
        
        // 发布启动完成事件
        listeners.started(context);
        callRunners(context, args);
    } catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }
    
    listeners.running(context);
    return context;
}

3.2 创建应用上下文

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

protected ConfigurableApplicationContext createApplicationContext() {
    Class<?> contextClass = this.applicationContextClass;
    if (contextClass == null) {
        try {
            switch (this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                    break;
                case REACTIVE:
                    contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                    break;
                default:
                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
            }
        } catch (ClassNotFoundException ex) {
            // 异常处理
        }
    }
    return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

3.3 前置处理与Bean定义加载

prepareContext()方法完成以下工作:

  1. 注册主配置类到Bean定义
  2. 发布ApplicationContextInitializedEvent事件
  3. 执行ApplicationContextInitializer初始化逻辑
  4. 发布ApplicationPreparedEvent事件
private void prepareContext(ConfigurableApplicationContext context,
        ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
        Banner printedBanner) {
    // 1. 关联环境配置
    context.setEnvironment(environment);
    
    // 2. 后置处理上下文
    postProcessApplicationContext(context);
    
    // 3. 执行初始化器
    applyInitializers(context);
    
    // 4. 触发contextPrepared事件
    listeners.contextPrepared(context);
    
    // 5. 注册启动参数bean
    if (this.registerShutdownHook) {
        context.registerShutdownHook();
    }
    
    // 6. 准备Bean定义加载
    prepareBeanFactory(context.getBeanFactory());
}

3.4 刷新应用上下文

refreshContext()最终调用Spring Framework的AbstractApplicationContext.refresh()

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 1. 准备刷新(记录启动时间、状态等)
        prepareRefresh();
        
        // 2. 获取新的BeanFactory
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        
        // 3. 准备BeanFactory(注册标准环境Bean等)
        prepareBeanFactory(beanFactory);
        
        try {
            // 4. 后置处理BeanFactory
            postProcessBeanFactory(beanFactory);
            
            // 5. 执行BeanFactoryPostProcessor
            invokeBeanFactoryPostProcessors(beanFactory);
            
            // 6. 注册BeanPostProcessor
            registerBeanPostProcessors(beanFactory);
            
            // 7. 初始化MessageSource
            initMessageSource();
            
            // 8. 初始化事件广播器
            initApplicationEventMulticaster();
            
            // 9. 模板方法(子类实现)
            onRefresh();
            
            // 10. 注册监听器
            registerListeners();
            
            // 11. 完成BeanFactory初始化
            finishBeanFactoryInitialization(beanFactory);
            
            // 12. 完成刷新(发布ContextRefreshedEvent)
            finishRefresh();
        } catch (BeansException ex) {
            // 异常处理...
        }
    }
}

SpringBoot在onRefresh()阶段启动内嵌服务器

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) {
        // 从BeanFactory获取WebServerFactory
        ServletWebServerFactory factory = getWebServerFactory();
        
        // 创建WebServer(如Tomcat)
        this.webServer = factory.getWebServer(getSelfInitializer());
    }
    else if (servletContext != null) {
        try {
            getSelfInitializer().onStartup(servletContext);
        } catch (ServletException ex) {
            // 异常处理
        }
    }
    initPropertySources();
}

3.5 后置处理与启动完成

protected void afterRefresh(ConfigurableApplicationContext context,
        ApplicationArguments args) {
    // 1. 执行ApplicationRunner和CommandLineRunner
    callRunners(context, args);
}

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

4. 关键扩展点分析

SpringBoot提供的主要扩展机制:

扩展点类型 加载时机 典型用途
ApplicationContextInitializer 上下文准备阶段 环境预处理、属性源配置
ApplicationListener 全生命周期 事件监听、启动日志记录
BeanPostProcessor Bean初始化阶段 Bean代理、属性修改
EnvironmentPostProcessor 环境准备阶段 自定义属性源加载
SpringApplicationRunListener 运行过程关键节点 启动监控、性能统计

自定义扩展示例:

// 在META-INF/spring.factories中定义
org.springframework.context.ApplicationContextInitializer=\
  com.example.MyInitializer

public class MyInitializer implements 
    ApplicationContextInitializer<ConfigurableApplicationContext> {
    
    @Override
    public void initialize(ConfigurableApplicationContext context) {
        // 添加自定义属性源
        context.getEnvironment()
            .getPropertySources()
            .addLast(new MyPropertySource());
    }
}

5. 与内嵌容器的整合

SpringBoot 2.0.6支持的内嵌容器启动流程:

  1. 自动配置触发:通过ServletWebServerFactoryAutoConfiguration配置
  2. 工厂Bean创建:根据类路径依赖选择Tomcat/Jetty/Undertow
  3. 端口绑定:通过ServerProperties配置网络参数
  4. 上下文准备:将DispatcherServlet注册到容器
@AutoConfiguration
@ConditionalOnClass(Servlet.class)
@EnableConfigurationProperties(ServerProperties.class)
public class ServletWebServerFactoryAutoConfiguration {

    @Bean
    @ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
    public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
        return new TomcatServletWebServerFactory();
    }
    
    // Jetty和Undertow的类似配置...
}

容器启动时序图:

sequenceDiagram
    participant SpringApplication
    participant WebServerFactory
    participant WebServer
    
    SpringApplication->>WebServerFactory: getWebServer()
    WebServerFactory->>WebServer: 创建实例
    WebServer->>WebServer: 配置连接器
    WebServer->>WebServer: 部署DispatcherServlet
    WebServer->>WebServer: 启动线程池
    WebServer-->>SpringApplication: 返回实例

6. 总结

SpringBoot 2.0.6的启动流程可概括为三大阶段:

  1. 环境准备阶段

    • 推断应用类型
    • 加载扩展组件
    • 初始化运行时环境
  2. 上下文创建阶段

    • 创建合适的ApplicationContext
    • 准备Bean定义
    • 执行自动配置
  3. 容器启动阶段

    • 刷新Spring上下文
    • 启动内嵌Web容器
    • 执行Runner组件

关键优化点: - 合理使用@Lazy延迟初始化降低启动耗时 - 通过spring.autoconfigure.exclude过滤不需要的自动配置 - 使用spring.config.location指定外部配置提升灵活性

通过深入理解启动流程,开发者可以更好地: - 定制化SpringBoot应用启动行为 - 优化应用启动性能 - 处理复杂的初始化依赖问题 “`

推荐阅读:
  1. hive的执行流程
  2. 数据执行保护-run a dll as an app

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

spring

上一篇:Schtask计划任务的相关操作方法

下一篇:MySQL中的隐藏列的具体查看方法

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》