# SpringApplication.run()阶段

# 创建SpringApplication对象

  1. 创建实例

    Class<?> instanceClass = ClassUtils.forName(name, classLoader)
    
    1

    其中classLoader可以通过ClassUtils.getDefaultClassLoader()获取,或者是SpringApplication类中的public ClassLoader getClassLoader(){}方法

  2. 断言某个父类型是否是可分配子某个子类型,如果不是,也就是subType不是superType的实例,那么这个代码会抛出一个异常

    Assert.isAssignable(Class<?> superType, Class<?> subType);

运行SpringApplication.run()的时候,在创建SpringApplication实例,最终会执行下面这个构造器

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
2
3
4
5
6
7
8
9
10
11

在此构造器中,会初始化ApplicationListener类型的监听器,ApplicationContextInitializer以及BootstrapRegistryInitializer,他们都是通过类的全限定名称获取的,通过private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {}方法,返回一个实例化的对象集合

,如果我们想要增加一些自己的ApplicationListener类型的监听器,我们只需要实现这个对应的接口就行

在对this.mainApplicationClass赋值的时候,是调用下面这个方法

private Class<?> deduceMainApplicationClass() {
    try {
        StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
        for (StackTraceElement stackTraceElement : stackTrace) {
            if ("main".equals(stackTraceElement.getMethodName())) {
                return Class.forName(stackTraceElement.getClassName());
            }
        }
    }
    catch (ClassNotFoundException ex) {
        // Swallow and continue
    }
    return null;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

其实也就是遍历找到我们自己的类,这个主类调用SpringApplication.run()方法,启动springboot

# 执行run()方法

在此run()方法中,会先创建一个开始时间,官方是调用这个方法

long startTime = System.nanoTime();
1

然后会创建一个引导程序bootstrapcreateBootstrapContext()方法是通过从上一个new对象获取到的bootstrapRegistryInitializers中获取的

DefaultBootstrapContext bootstrapContext = createBootstrapContext();
1

然后设置系统属性configureHeadlessProperty(),在此方法中,主要调用System.setProperty(...)方法进行设置

然后会获取运行时的监听器

SpringApplicationRunListeners listeners = getRunListeners(args)
1

需要注意的是,获取运行时的监听器,并不是上一步new对象获取的setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));,在此处获取运行时监听器是获取SpringApplicationRunListener这个类,方法为getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),最终会new SpringApplicationRunListeners()一个新的对象,然后调用此运行时监听器中的starting()方法,开始监听器

# 准备环境

ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments)
1
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
                                                   DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
    // Create and configure the environment
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    ConfigurationPropertySources.attach(environment);
    listeners.environmentPrepared(bootstrapContext, environment);
    DefaultPropertiesPropertySource.moveToEnd(environment);
    Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
                 "Environment prefix cannot be set via properties.");
    bindToSpringApplication(environment);
    if (!this.isCustomEnvironment) {
        environment = convertEnvironment(environment);
    }
    ConfigurationPropertySources.attach(environment);
    return environment;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

先获取或者创建(如果没有ConfigurableEnvironment环境对象的话)一个环境,ConfigurableEnvironment environment = getOrCreateEnvironment()对应的源码为

private ConfigurableEnvironment getOrCreateEnvironment() {
    if (this.environment != null) {
        return this.environment;
    }
    switch (this.webApplicationType) {
        case SERVLET:
            return new ApplicationServletEnvironment();
        case REACTIVE:
            return new ApplicationReactiveWebEnvironment();
        default:
            return new ApplicationEnvironment();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

这个也就是选择根据当前的配置,选择一个合适的环境,this.webApplicationTypeSERVLET,所以会创建一个servlet环境,REACTIVE是一个响应式,如果两个都不满足,那么就创建一个默认的,无论在switch中选择哪一个,他们最终都是StandardEnvironment类型的对象,此StandardEnvironment对象的祖宗类是ConfigurableEnvironment,也就是this.environment对应的类型。并且在最后将环境绑定到应用的过程中,会将获取到的环境转换成ConfigurableEnvironment对象(子到父的过程)

如果我们想要自定义环境的话,可以调用SpringApplication对象中的setEnvironment(ConfigurableEnvironment)方法,如果没有调用此方法自定义环境,那么environment就是null,不建议自定义环境

# 配置环境

getOrCreateEnvironment()方法中,会进行下面代码,配置环境

protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
    if (this.addConversionService) {
        environment.setConversionService(new ApplicationConversionService());
    }
    configurePropertySources(environment, args);
    configureProfiles(environment, args);
}
1
2
3
4
5
6
7

在上一步中,已经创建了预准备环境,选择一个合适的StandardEnvironment对象,那么在这一步就需要对此预准备环境进行配置(我并没有发现什么)

判断一个对象是否是某个Class的实例,可以使用Assert.isInstanceOf(Class, instance)进行判断,如果判断失败,会抛出一个异常

Assert.state(boolean,message)此方法是断言状态,如果boolean为false,那么会抛出一个异常,异常中的message就是此方法中的message

# 将环境绑定到应用

bindToSpringApplication(environment);

此方法的代码为,为了演示方便,我在application.yml文件中,添加了以下以spring.main开头的配置

spring:
  main:
    allow-circular-references: true
1
2
3
protected void bindToSpringApplication(ConfigurableEnvironment environment) {
    try {
        Binder.get(environment).bind("spring.main", Bindable.ofInstance(this));
    }
    catch (Exception ex) {
        throw new IllegalStateException("Cannot bind to SpringApplication", ex);
    }
}
1
2
3
4
5
6
7
8
  1. 通过当前环境,获取到一个Binder对象

bind()的方法如下

public <T> BindResult<T> bind(String name, Bindable<T> target) {
    return bind(ConfigurationPropertyName.of(name), target, null);
}
1
2
3

我的判断:这一步应该就是配置以spring.main开头的配置,将这些配置绑定到当前环境中

# 打印banner

Banner printedBanner = printBanner(environment)
1

# 创建应用的上下文context

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

会根据我们预准备环境中获取的环境,创建对应的context,然后将ApplicationStartup添加到此context

当创建好了context之后,会预准备context,和预准备环境差不多,会进行context的相关配置,代码如下

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);
    bootstrapContext.close(context);
    if (this.logStartupInfo) {
        logStartupInfo(context.getParent() == null);
        logStartupProfileInfo(context);
    }
    // Add boot specific singleton beans
    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    if (printedBanner != null) {
        beanFactory.registerSingleton("springBootBanner", printedBanner);
    }
    if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
        ((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
        if (beanFactory instanceof DefaultListableBeanFactory) {
            ((DefaultListableBeanFactory) beanFactory)
            .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
    }
    if (this.lazyInitialization) {
        context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
    }
    // Load the sources
    Set<Object> sources = getAllSources();
    Assert.notEmpty(sources, "Sources must not be empty");
    load(context, sources.toArray(new Object[0]));
    listeners.contextLoaded(context);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

将此context添加到applicationRunListener等对象中

根据我们的配置信息,设置是否允许循环引用

((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences)
1
# 刷新context
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
shutdownHook.registerApplicationContext(context);
}
refresh(context);
}

protected void refresh(ConfigurableApplicationContext applicationContext) {
applicationContext.refresh();
}
1
2
3
4
5
6
7
8
9
10