三、Spring Boot源码分析

134 阅读2分钟

一、Spring Boot启动jar包原理


ioc容器带动了内嵌tomcat的启动

1、SpringApplication初始化阶段

1)编写Spring Boot启动类

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

2)SpringApplication初始化是通过调用其静态方法run(Class<?> primarySource, String... args)来启动应用

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    return run(new Class[]{primarySource}, args);
}

3)如果稍微留心观察,SpringApplication对象构造过程就在其中

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    return (new SpringApplication(primarySources)).run(args);
}

4)SpringApplication构造过程

public SpringApplication(Class<?>... primarySources) {
    this((ResourceLoader)null, primarySources);
}

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    // ...
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    // 保存主配置类primarySources
    this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
    // 推断Web应用类型
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 加载Spring应用上下文初始化器
    this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 加载Spring应用事件监听器
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
    // 推断应用引导类
    this.mainApplicationClass = this.deduceMainApplicationClass();
}

至此,SpringApplication对象创建完成

2、SpringApplication运行阶段

1)传入args参数,调用SpringApplication对象的run()方法

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    // 创建一个容器对象
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
    this.configureHeadlessProperty();
    // 去classpath下的meta-info/spring.factories下获取SpringApplicationRunListener监听器(事件发布监听器)
    SpringApplicationRunListeners listeners = this.getRunListeners(args);
    listeners.starting();

    Collection exceptionReporters;
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        // 准备环境
        ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
        this.configureIgnoreBeanInfo(environment);
        // 打印Spring Boot图标
        Banner printedBanner = this.printBanner(environment);
        // 根据当前是否为Web环境来决定是创建Web容器还是普通的IOC容器
        context = this.createApplicationContext();
        // 去classpath下的meta-info/spring.factories下获取异常报告类SpringBootExceptionReporter
        exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
        // 容器预准备流程
        this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        // 
        this.refreshContext(context);
        this.afterRefresh(context, applicationArguments);
        stopWatch.stop();
        if (this.logStartupInfo) {
            (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
        }

        listeners.started(context);
        this.callRunners(context, applicationArguments);
    } catch (Throwable var10) {
        this.handleRunFailure(context, var10, exceptionReporters, listeners);
        throw new IllegalStateException(var10);
    }

    try {
        listeners.running(context);
        return context;
    } catch (Throwable var9) {
        this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
        throw new IllegalStateException(var9);
    }
}

2)

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
    // 获取或者创建一个环境
    ConfigurableEnvironment environment = this.getOrCreateEnvironment();
    // 配置环境,把命令行参数配置到环境中去
    this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
    ConfigurationPropertySources.attach((Environment)environment);
    // 循环调用SpringApplicationRunListener.environmentPrepared()环境预准备方法
    listeners.environmentPrepared((ConfigurableEnvironment)environment);
    // 把环境对象绑定到SpringApplication对象上
    this.bindToSpringApplication((ConfigurableEnvironment)environment);
    if (!this.isCustomEnvironment) {
        environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
    }

    ConfigurationPropertySources.attach((Environment)environment);
    return (ConfigurableEnvironment)environment;
}

二、Spring Boot启动war包原理


外置的tomcat带动了ioc容器的启动

三、多线程debug