spring boot启动流程

fxz大约 29 分钟

spring boot启动流程

省流

  • 创建引导上下文。引导上下文的作用就是在应用上下文创建之前,可以在“启动时”和“Environment的后处理期间”获取到它,直到ApplicationContext准备好后它就不可用了。这个上下文的可以用于为创建成本高昂的单例,或需要在容器初始化之前使用的单例,提供延迟访问的机制。
  • 获取spring应用程序运行监听器。这个监听器可以在springboot启动过程中发布一些事件,比如:启动时、环境的后置处理。
  • 构造环境对象。首先会把命令行参数搞里面,然后会通过环境的后置处理器加载配置。
  • 创建应用程序上下文。这时会把应用程序上下文配置好,同时关闭引导上下文。
  • 刷新应用程序上下文。
  • 回调runners接口。
  • 发布应用就绪事件。
public ConfigurableApplicationContext run(String... args) {
    long startTime = System.nanoTime();

    /**
     * 构造 DefaultBootstrapContext,会使用 BootstrapRegistryInitializer 对其初始化
     *
     * 是在构造器收集好有哪些 BootstrapRegistryInitializer
     *      {@link SpringApplication#SpringApplication(ResourceLoader, Class[])}
     *
     * DefaultBootstrapContext 的生命周期范围是 IOC容器refresh之前
     * */
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();

    ConfigurableApplicationContext context = null;
    // 设置一个系统属性
    configureHeadlessProperty();

    /**
     * SpringApplicationRunListeners 是 SpringApplicationRunListener 的注册器,具体干活的是 SpringApplicationRunListener
     * 而具体有哪些 SpringApplicationRunListener 是读取 META-INF/spring.factories 中key为 SpringApplicationRunListener.class.getName() 的信息
     *
     * tips:这就是观察者模式
     * */
    SpringApplicationRunListeners listeners = getRunListeners(args);
    // 回调 SpringApplicationRunListener#starting 方法,可以在这个方法装饰 bootstrapContext
    listeners.starting(bootstrapContext, this.mainApplicationClass);

    try {
        // 装饰一下 args
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

        /**
         * 构造出 ConfigurableEnvironment
         *
         * 1. 可以使用 ApplicationContextFactory 来生成 ConfigurableEnvironment
         * 2. 回调 SpringApplicationRunListener#environmentPrepared 配置 ConfigurableEnvironment
         * 3. 修改属性的访问顺序为: 命令行参数 -> 系统属性 -> 环境变量 ... -> 默认属性(默认是空的)
         * */
        ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);

        // 设置一个名叫 spring.beaninfo.ignore 的系统属性
        configureIgnoreBeanInfo(environment);

        /**
         * 构造出 Banner 并打印出banner的内容
         * 会尝试从 environment 获取属性指定的文件
         *  spring.banner.image.location
         *  spring.banner.location
         * 或者是 banner.[jpg | gif | png | txt]对应的文件
         * 作为要输出的内容
         * */
        Banner printedBanner = printBanner(environment);

        /**
         * 会根据环境推断出应该创建什么类型的IOC容器:
         *  - AnnotationConfigApplicationContext
         *  - AnnotationConfigServletWebServerApplicationContext
         *  - ApplicationReactiveWebEnvironment
         *
         * 会回调 {@link ApplicationContextFactory#create(WebApplicationType)} 方法构造出 context
         * */
        context = createApplicationContext();
        context.setApplicationStartup(this.applicationStartup);

        /**
         * 配置 IOC 容器:
         *  1. 给IOC容器设置上 environment
         
         *  2. 给IOC容器设置上 ResourceLoader、ConversionService
         
         *  3. 回调 ApplicationContextInitializer、SpringApplicationRunListener、bootstrapContext 方法
         *      3.1 初始化IOC容器    ApplicationContextInitializer#initialize
         *      3.2 配置IOC容器     SpringApplicationRunListener#contextPrepared
         *      3.3 完成DefaultBootstrapContext的生命周期      DefaultBootstrapContext#close
         *      3.4 IOC容器配置好了   SpringApplicationRunListener#contextLoaded
         *
         *  4. 添加单例bean:springApplicationArguments、springBootBanner
         
         *  5. 设置两个属性 allowCircularReferences、allowBeanDefinitionOverriding
         
         *  6. 添加两个BeanFactoryPostProcessor:
         *          LazyInitializationBeanFactoryPostProcessor:这个是用来判断是否需要给补全信息的 `beanDefinition.setLazyInit(true);`
         *          PropertySourceOrderingBeanFactoryPostProcessor:这个是用来将名叫 defaultProperties 的 PropertySource 移到 最后面的,也就是属性访问的优先级最低
         
         *  7. 将启动类添加到IOC容器中,说白了就是注册配置类
         * */
        prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);

        // 刷新IOC容器
        refreshContext(context);

        // 预留的模板方法
        afterRefresh(context, applicationArguments);

        Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
        }
        /**
         * 回调 SpringApplicationRunListener#started 方法(IOC容器启动耗时)
         * {@link SpringApplicationRunListener#started(ConfigurableApplicationContext, Duration)}
         * */
        listeners.started(context, timeTakenToStartup);

        // 回调 容器中类型是 ApplicationRunner、CommandLineRunner 的bean的方法
        callRunners(context, applicationArguments);
    } catch (Throwable ex) {
        /**
         * 处理异常情况:
         * 1. 使用 context 发布 ExitCodeEvent 事件
         * 2. 回调 SpringApplicationRunListener#failed 方法
         * */
        handleRunFailure(context, ex, listeners);
        throw new IllegalStateException(ex);
    }
    try {
        // 启动耗时
        Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
        /**
         * 回调 SpringApplicationRunListener#ready 方法(SpringBoot启动耗时)
         * {@link SpringApplicationRunListener#ready(ConfigurableApplicationContext, Duration)}
         * */
        listeners.ready(context, timeTakenToReady);
    } catch (Throwable ex) {
        handleRunFailure(context, ex, null);
        throw new IllegalStateException(ex);
    }
    // 返回IOC容器
    return context;
}

创建引导上下文

DefaultBootstrapContext 作为 BootstrapContext 接口的默认实现,主要用于在 Spring Boot 应用启动的各个阶段中发布不同类型的事件。在 Spring Boot 启动过程中,会逐步加载配置和组件,并在各个阶段发布相应的事件。开发人员可以通过监听这些事件,来进行特定的初始化或程序逻辑操作。

DefaultBootstrapContext bootstrapContext = createBootstrapContext();
SpringApplication:
private DefaultBootstrapContext createBootstrapContext() {
      // 创建引导上下文
    DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();    
      // 初始化器初始化引导上下文
    this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
      // 返回创建的引导上下文
    return bootstrapContext;
}
/**
 * 一个 {@link BootstrapContext},它还通过
 * {@link BootstrapRegistry} 接口。
 *
 * @author Phillip Webb
 * @see BootstrapRegistry
 * @see BootstrapContext
 * @see DefaultBootstrapContext
 * @since 2.4.0
 */
public interface ConfigurableBootstrapContext extends BootstrapRegistry, BootstrapContext {

}
/**
 * 在启动期间可用的简单对象注册表和 {@link Environment}
 * 后处理,直到 {@link ApplicationContext} 准备好为止。
 * <p>
 * 可用于注册创建成本高昂或需要共享的实例
 * 之前 {@link ApplicationContext} 可用。
 * <p>
 * 注册表使用 {@link Class} 作为键,这意味着只有
 * 可以存储给定的类型。
 * <p>
 * {@link #addCloseListener(ApplicationListener)} 方法可用于添加监听器
 * 可以在 {@link BootstrapContext} 关闭且
 * {@link ApplicationContext} 已做好充分准备。例如,实例可以选择
 * 将自己注册为常规的 Spring bean,以便它可供应用程序使用
 * 用。
 *
 * @author Phillip Webb
 * @see BootstrapContext
 * @see ConfigurableBootstrapContext
 * @since 2.4.0
 */
public interface BootstrapRegistry {

    /**
     * 向注册表注册特定类型。如果指定的类型已经
     * 已注册且尚未作为 {@link Scope#SINGLETON 单例}获得,它
     * 将被替换。
     *
     * @param <T>              the instance type
     * @param type             the instance type
     * @param instanceSupplier the instance supplier
     */
    <T> void register(Class<T> type, InstanceSupplier<T> instanceSupplier);

    /**
     * 如果尚未向注册表注册特定类型,请向注册表注册该类型。
     *
     * @param <T>              the instance type
     * @param type             the instance type
     * @param instanceSupplier the instance supplier
     */
    <T> void registerIfAbsent(Class<T> type, InstanceSupplier<T> instanceSupplier);

    /**
     * 如果给定类型存在注册,则返回。
     *
     * @param <T>  the instance type
     * @param type the instance type
     * @return {@code true} if the type has already been registered
     */
    <T> boolean isRegistered(Class<T> type);

    /**
     * 返回给定类型的任何现有 {@link InstanceSupplier}。
     *
     * @param <T>  the instance type
     * @param type the instance type
     * @return the registered {@link InstanceSupplier} or {@code null}
     */
    <T> InstanceSupplier<T> getRegisteredInstanceSupplier(Class<T> type);

    /**
     * 添加一个 {@link ApplicationListener},它将使用
     * {@link BootstrapContextClosedEvent}{@link BootstrapContext} 关闭且
     * {@link ApplicationContext} 已准备好。
     *
     * @param listener the listener to add
     */
    void addCloseListener(ApplicationListener<BootstrapContextClosedEvent> listener);

    /**
     * Supplier used to provide the actual instance when needed.
     *
     * @param <T> the instance type
     * @see Scope
     */
    @FunctionalInterface
    interface InstanceSupplier<T> {

       /**
        * Factory method used to create the instance when needed.
        *
        * @param context the {@link BootstrapContext} which may be used to obtain other
        *                bootstrap instances.
        * @return the instance
        */
       T get(BootstrapContext context);

       /**
        * Return the scope of the supplied instance.
        *
        * @return the scope
        * @since 2.4.2
        */
       default Scope getScope() {
          return Scope.SINGLETON;
       }

       /**
        * Return a new {@link InstanceSupplier} with an updated {@link Scope}.
        *
        * @param scope the new scope
        * @return a new {@link InstanceSupplier} instance with the new scope
        * @since 2.4.2
        */
       default InstanceSupplier<T> withScope(Scope scope) {
          Assert.notNull(scope, "Scope must not be null");
          InstanceSupplier<T> parent = this;
          return new InstanceSupplier<T>() {

             @Override
             public T get(BootstrapContext context) {
                return parent.get(context);
             }

             @Override
             public Scope getScope() {
                return scope;
             }

          };
       }

       /**
        * Factory method that can be used to create an {@link InstanceSupplier} for a
        * given instance.
        *
        * @param <T>      the instance type
        * @param instance the instance
        * @return a new {@link InstanceSupplier}
        */
       static <T> InstanceSupplier<T> of(T instance) {
          return (registry) -> instance;
       }

       /**
        * Factory method that can be used to create an {@link InstanceSupplier} from a
        * {@link Supplier}.
        *
        * @param <T>      the instance type
        * @param supplier the supplier that will provide the instance
        * @return a new {@link InstanceSupplier}
        */
       static <T> InstanceSupplier<T> from(Supplier<T> supplier) {
          return (registry) -> (supplier != null) ? supplier.get() : null;
       }

    }

    /**
     * The scope of an instance.
     *
     * @since 2.4.2
     */
    enum Scope {

       /**
        * A singleton instance. The {@link InstanceSupplier} will be called only once and
        * the same instance will be returned each time.
        */
       SINGLETON,

       /**
        * A prototype instance. The {@link InstanceSupplier} will be called whenever an
        * instance is needed.
        */
       PROTOTYPE

    }

}
/**
 * 在启动期间可用的简单引导上下文和 {@link Environment}
 * 后处理,直到 {@link ApplicationContext} 准备好为止。
 * <p>
 * 提供对创建成本可能很高或需要的单例的延迟访问
 * 在 {@link ApplicationContext} 可用之前共享。
 *
 * @author Phillip Webb
 * @since 2.4.0
 */
public interface BootstrapContext {

    /**
     * 如果类型已注册,则从上下文中返回实例。实例
     * 如果以前未访问过,则将创建它。
     *
     * @param <T>  the instance type
     * @param type the instance type
     * @return the instance managed by the context
     * @throws IllegalStateException if the type has not been registered
     */
    <T> T get(Class<T> type) throws IllegalStateException;

    /**
     * 如果类型已注册,则从上下文中返回实例。实例
     * 如果以前未访问过,则将创建它。
     *
     * @param <T>   the instance type
     * @param type  the instance type
     * @param other the instance to use if the type has not been registered
     * @return the instance
     */
    <T> T getOrElse(Class<T> type, T other);

    /**
     * 如果类型已注册,则从上下文中返回实例。实例
     * 如果以前未访问过,则将创建它。
     *
     * @param <T>   the instance type
     * @param type  the instance type
     * @param other a supplier for the instance to use if the type has not been registered
     * @return the instance
     */
    <T> T getOrElseSupply(Class<T> type, Supplier<T> other);

    /**
     * 如果类型已注册,则从上下文中返回实例。实例
     * 如果以前未访问过,则将创建它。
     *
     * @param <T>               the instance type
     * @param <X>               the exception to throw if the type is not registered
     * @param type              the instance type
     * @param exceptionSupplier the supplier which will return the exception to be thrown
     * @return the instance managed by the context
     * @throws X                     if the type has not been registered
     * @throws IllegalStateException if the type has not been registered
     */
    <T, X extends Throwable> T getOrElseThrow(Class<T> type, Supplier<? extends X> exceptionSupplier) throws X;

    /**
     * 如果给定类型存在注册,则返回。
     *
     * @param <T>  the instance type
     * @param type the instance type
     * @return {@code true} if the type has already been registered
     */
    <T> boolean isRegistered(Class<T> type);

}
/**
 * Default {@link ConfigurableBootstrapContext} implementation.
 *
 * @author Phillip Webb
 * @since 2.4.0
 */
public class DefaultBootstrapContext implements ConfigurableBootstrapContext {

    private final Map<Class<?>, InstanceSupplier<?>> instanceSuppliers = new HashMap<>();

    private final Map<Class<?>, Object> instances = new HashMap<>();

    private final ApplicationEventMulticaster events = new SimpleApplicationEventMulticaster();

    @Override
    public <T> void register(Class<T> type, InstanceSupplier<T> instanceSupplier) {
       register(type, instanceSupplier, true);
    }

    @Override
    public <T> void registerIfAbsent(Class<T> type, InstanceSupplier<T> instanceSupplier) {
       register(type, instanceSupplier, false);
    }

    private <T> void register(Class<T> type, InstanceSupplier<T> instanceSupplier, boolean replaceExisting) {
       Assert.notNull(type, "Type must not be null");
       Assert.notNull(instanceSupplier, "InstanceSupplier must not be null");
       synchronized (this.instanceSuppliers) {    
             // 已经注册
          boolean alreadyRegistered = this.instanceSuppliers.containsKey(type);
             // 替换或者未注册
          if (replaceExisting || !alreadyRegistered) {
             Assert.state(!this.instances.containsKey(type), () -> type.getName() + " has already been created");
             this.instanceSuppliers.put(type, instanceSupplier);
          }
       }
    }

    @Override
    public <T> boolean isRegistered(Class<T> type) {
       synchronized (this.instanceSuppliers) {
          return this.instanceSuppliers.containsKey(type);
       }
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> InstanceSupplier<T> getRegisteredInstanceSupplier(Class<T> type) {
       synchronized (this.instanceSuppliers) {
          return (InstanceSupplier<T>) this.instanceSuppliers.get(type);
       }
    }

    @Override
    public void addCloseListener(ApplicationListener<BootstrapContextClosedEvent> listener) {
       this.events.addApplicationListener(listener);
    }

    @Override
    public <T> T get(Class<T> type) throws IllegalStateException {
       return getOrElseThrow(type, () -> new IllegalStateException(type.getName() + " has not been registered"));
    }

    @Override
    public <T> T getOrElse(Class<T> type, T other) {
       return getOrElseSupply(type, () -> other);
    }

    @Override
    public <T> T getOrElseSupply(Class<T> type, Supplier<T> other) {
       synchronized (this.instanceSuppliers) {
          InstanceSupplier<?> instanceSupplier = this.instanceSuppliers.get(type);
          return (instanceSupplier != null) ? getInstance(type, instanceSupplier) : other.get();
       }
    }

    @Override
    public <T, X extends Throwable> T getOrElseThrow(Class<T> type, Supplier<? extends X> exceptionSupplier) throws X {
       synchronized (this.instanceSuppliers) {
          InstanceSupplier<?> instanceSupplier = this.instanceSuppliers.get(type);
          if (instanceSupplier == null) {
             throw exceptionSupplier.get();
          }
          return getInstance(type, instanceSupplier);
       }
    }

    @SuppressWarnings("unchecked")
    private <T> T getInstance(Class<T> type, InstanceSupplier<?> instanceSupplier) {
       T instance = (T) this.instances.get(type);
       if (instance == null) {
          instance = (T) instanceSupplier.get(this);
          if (instanceSupplier.getScope() == Scope.SINGLETON) {
             this.instances.put(type, instance);
          }
       }
       return instance;
    }

    /**
     * Method to be called when {@link BootstrapContext} is closed and the
     * {@link ApplicationContext} is prepared.
     * @param applicationContext the prepared context
     */
    public void close(ConfigurableApplicationContext applicationContext) {
       this.events.multicastEvent(new BootstrapContextClosedEvent(this, applicationContext));
    }

}

其中bootstrapRegistryInitializers是在SpringApplication的构造中初始化的,通过Spring工厂加载。

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    ......

    // 读取 META-INF/spring.factories 中key为 BootstrapRegistryInitializer.class.getName() 的信息,然后反射实例化
    /**
     * 这是用来在 run 环节对 BootstrapRegistry 进行初始化的
     *    {@link SpringApplication#createBootstrapContext()}
     * */
    this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
         ......
}
SpringApplication: 

        // 从springfactores获取指定类型的实例
    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
        return getSpringFactoriesInstances(type, new Class<?>[]{});
    }

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = getClassLoader();

        // 读取 META-INF/spring.factories 中key为 type.getName() 的信息
        // Use names and ensure unique to protect against duplicates
        Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        // 实例化
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        // 排序
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }

        // 通过反射获取指定类的实例
    private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
                                                       ClassLoader classLoader, Object[] args, Set<String> names) {
        List<T> instances = new ArrayList<>(names.size());
        for (String name : names) {
            try {
                Class<?> instanceClass = ClassUtils.forName(name, classLoader);
                Assert.isAssignable(type, instanceClass);
                Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
                T instance = (T) BeanUtils.instantiateClass(constructor, args);
                instances.add(instance);
            } catch (Throwable ex) {
                throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
            }
        }
        return instances;
    }
SpringFactoriesLoader: 
    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";


        // 获取指定类型实例的全限定类名
    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
      ClassLoader classLoaderToUse = classLoader;
      if (classLoaderToUse == null) {
        classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
      }

      String factoryTypeName = factoryType.getName();

      return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
    }

    private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
      Map<String, List<String>> result = cache.get(classLoader);
      if (result != null) {
        return result;
      }

      result = new HashMap<>();
      try {
        Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
        while (urls.hasMoreElements()) {
          URL url = urls.nextElement();
          UrlResource resource = new UrlResource(url);
          Properties properties = PropertiesLoaderUtils.loadProperties(resource);
          for (Map.Entry<?, ?> entry : properties.entrySet()) {
            String factoryTypeName = ((String) entry.getKey()).trim();
            String[] factoryImplementationNames =
                StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
            for (String factoryImplementationName : factoryImplementationNames) {
              result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
                  .add(factoryImplementationName.trim());
            }
          }
        }

        // Replace all lists with unmodifiable lists containing unique elements
        result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
            .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
        cache.put(classLoader, result);
      }
      catch (IOException ex) {
        throw new IllegalArgumentException("Unable to load factories from location [" +
            FACTORIES_RESOURCE_LOCATION + "]", ex);
      }
      return result;
    }

获取Spring运行监听器

/**
 * SpringApplicationRunListeners 是 SpringApplicationRunListener 的注册器,具体干活的是 SpringApplicationRunListener
 * 而具体有哪些 SpringApplicationRunListener 是读取 META-INF/spring.factories 中key为 SpringApplicationRunListener.class.getName() 的信息
 * */
SpringApplicationRunListeners listeners = getRunListeners(args);
private SpringApplicationRunListeners getRunListeners(String[] args) {
    Class<?>[] types = new Class<?>[]{SpringApplication.class, String[].class};
    return new SpringApplicationRunListeners(logger,
            getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
            this.applicationStartup
    );
}

应用启动回调

// 回调 SpringApplicationRunListener#starting 方法,可以在这个方法装饰 bootstrapContext
listeners.starting(bootstrapContext, this.mainApplicationClass);
SpringApplicationRunListeners:

void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
    doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
          (step) -> {
             if (mainApplicationClass != null) {
                step.tag("mainApplicationClass", mainApplicationClass.getName());
             }
          });
}

private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
            Consumer<StartupStep> stepAction) {
        StartupStep step = this.applicationStartup.start(stepName);
        this.listeners.forEach(listenerAction);
        if (stepAction != null) {
            stepAction.accept(step);
        }
        step.end();
    }

在spring-boot-project的META-INF下默认配置:

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
@Override
public void starting(ConfigurableBootstrapContext bootstrapContext) {
    this.initialMulticaster
          .multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
}

创建命令行参数对象

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
DefaultApplicationArguments:

public DefaultApplicationArguments(String... args) {
    Assert.notNull(args, "Args must not be null");
    this.source = new Source(args);
    this.args = args;
}
Source:

private static class Source extends SimpleCommandLinePropertySource {

    Source(String[] args) {
       super(args);
    }

    @Override
    public List<String> getNonOptionArgs() {
       return super.getNonOptionArgs();
    }

    @Override
    public List<String> getOptionValues(String name) {
       return super.getOptionValues(name);
    }

}
public class SimpleCommandLinePropertySource extends CommandLinePropertySource<CommandLineArgs> {

    /**
     * Create a new {@code SimpleCommandLinePropertySource} having the default name
     * and backed by the given {@code String[]} of command line arguments.
     * @see CommandLinePropertySource#COMMAND_LINE_PROPERTY_SOURCE_NAME
     * @see CommandLinePropertySource#CommandLinePropertySource(Object)
     */
    public SimpleCommandLinePropertySource(String... args) {
       super(new SimpleCommandLineArgsParser().parse(args));
    }

    /**
     * Create a new {@code SimpleCommandLinePropertySource} having the given name
     * and backed by the given {@code String[]} of command line arguments.
     */
    public SimpleCommandLinePropertySource(String name, String[] args) {
       super(name, new SimpleCommandLineArgsParser().parse(args));
    }

    /**
     * Get the property names for the option arguments.
     */
    @Override
    public String[] getPropertyNames() {
       return StringUtils.toStringArray(this.source.getOptionNames());
    }

    @Override
    protected boolean containsOption(String name) {
       return this.source.containsOption(name);
    }

    @Override
    @Nullable
    protected List<String> getOptionValues(String name) {
       return this.source.getOptionValues(name);
    }

    @Override
    protected List<String> getNonOptionArgs() {
       return this.source.getNonOptionArgs();
    }

}
class SimpleCommandLineArgsParser {


    public CommandLineArgs parse(String... args) {
        CommandLineArgs commandLineArgs = new CommandLineArgs();

        for (String arg : args) {
            // 可选参数
            if (arg.startsWith("--")) {
                String optionText = arg.substring(2);
                String optionName;
                String optionValue = null;
                int indexOfEqualsSign = optionText.indexOf('=');
                if (indexOfEqualsSign > -1) {
                    optionName = optionText.substring(0, indexOfEqualsSign);
                    optionValue = optionText.substring(indexOfEqualsSign + 1);
                }
                else {
                    optionName = optionText;
                }
                if (optionName.isEmpty()) {
                    throw new IllegalArgumentException("Invalid argument syntax: " + arg);
                }
                commandLineArgs.addOptionArg(optionName, optionValue);
            }
            else {
                // 非可选参数
                commandLineArgs.addNonOptionArg(arg);
            }
        }

        return commandLineArgs;
    }

}

构造环境对象

            /**
             * 构造出 ConfigurableEnvironment
             *
             * 1. 可以使用 ApplicationContextFactory 来生成 ConfigurableEnvironment
             
             * 2. 回调 SpringApplicationRunListener#environmentPrepared 配置 ConfigurableEnvironment
             
             * 3. 修改属性的访问顺序为: 命令行参数 -> 系统属性 -> 环境变量 ... -> 默认属性(默认是空的)
             * */
            ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
 private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
                                                       DefaultBootstrapContext bootstrapContext,
                                                       ApplicationArguments applicationArguments) {
        /**
         * 创建出 ConfigurableEnvironment 
         * 在Servlet环境下是ApplicationServletEnvironment
         * */
        ConfigurableEnvironment environment = getOrCreateEnvironment();

        /**
         * 配置Environment,其实就是扩展Environment能访问的属性信息
         *         访问顺序:命令行参数 -> ... -> 默认属性
         * */
        configureEnvironment(environment, applicationArguments.getSourceArgs());

        // 将 ConfigurationPropertySourcesPropertySource 放到第一个位置
        ConfigurationPropertySources.attach(environment);

       /**
         * 回调 {@link SpringApplicationRunListener#environmentPrepared(ConfigurableBootstrapContext, ConfigurableEnvironment)}
         * 对 environment 进行配置
         * */
        listeners.environmentPrepared(bootstrapContext, environment);

        // 移动 defaultProperties 到最后,即优先级最低
        DefaultPropertiesPropertySource.moveToEnd(environment);
        Assert.state(
                !environment.containsProperty("spring.main.environment-prefix"),
                "Environment prefix cannot be set via properties."
        );

        // 将当前的 SpringApplication 实例绑定到Spring Boot应用程序的配置环境 (ConfigurableEnvironment) 中的 spring.main 属性下
        bindToSpringApplication(environment);

        if (!this.isCustomEnvironment) {
            EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
            // 转换成 ConfigurableEnvironment 类型的
            environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
        }

        // 同上
        ConfigurationPropertySources.attach(environment);
        return environment;
    }

配置环境

SpringApplication:


    protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
        if (this.addConversionService) {
            environment.setConversionService(new ApplicationConversionService());
        }

        /**
         * 扩展 environment 访问的属性
         *
         * 访问顺序:命令行参数 -> ... -> 默认属性
         *
         * */
        configurePropertySources(environment, args);

        // 模板方法,空实现
        configureProfiles(environment, args);
    }


    /**
     * 在此应用程序的环境中添加、删除或重新排序任何 {@link PropertySource}。
     *
     * @param environment this application's environment
     * @param args        arguments passed to the {@code run} method
     * @see #configureEnvironment(ConfigurableEnvironment, String[])
     */
    protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
        MutablePropertySources sources = environment.getPropertySources();

        if (!CollectionUtils.isEmpty(this.defaultProperties)) {
            // 将 defaultProperties 装饰成 propertySource 然后注册到 sources 中(放在最后)
            DefaultPropertiesPropertySource.addOrMerge(this.defaultProperties, sources);
        }

        // 将 args 构造成 SimpleCommandLinePropertySource 然后注册到 sources 中(放到前面)
        if (this.addCommandLineProperties && args.length > 0) {
            String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
            if (sources.contains(name)) {
                PropertySource<?> source = sources.get(name);
                CompositePropertySource composite = new CompositePropertySource(name);
                composite.addPropertySource(
                        new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
                composite.addPropertySource(source);
                sources.replace(name, composite);
            } else {
                // 放到前面
                sources.addFirst(new SimpleCommandLinePropertySource(args));
            }
        }
    }

添加附加属性

    ConfigurationPropertySources:

    public static void attach(Environment environment) {
        Assert.isInstanceOf(ConfigurableEnvironment.class, environment);

        MutablePropertySources sources = ((ConfigurableEnvironment) environment).getPropertySources();

        // 拿到叫这个名字的 configurationProperties PropertySource
        PropertySource<?> attached = getAttached(sources);
        // 这个判断是为了防止重复下面的操作
        if (attached == null || !isUsingSources(attached, sources)) {
            // 装饰成 ConfigurationPropertySourcesPropertySource
            attached = new ConfigurationPropertySourcesPropertySource(ATTACHED_PROPERTY_SOURCE_NAME,
                    new SpringConfigurationPropertySources(sources));
        }
        sources.remove(ATTACHED_PROPERTY_SOURCE_NAME);
        // 放到前面
        sources.addFirst(attached);
    }

❓发布环境准备事件

todo 这里是非常核心的,设计配置的加载,需要专门研究一下。

    SpringApplicationRunListeners:
    void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
        doWithListeners("spring.boot.application.environment-prepared",
                (listener) -> listener.environmentPrepared(bootstrapContext, environment));
    }



EventPublishingRunListener:
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
            ConfigurableEnvironment environment) {
        this.initialMulticaster.multicastEvent(
                new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment));
    }

创建应用程序上下文

    /**
             * 会根据环境推断出应该创建什么类型的IOC容器:
             *  - AnnotationConfigApplicationContext
             *  - AnnotationConfigServletWebServerApplicationContext
             *  - ApplicationReactiveWebEnvironment
             *
             * 会回调 {@link ApplicationContextFactory#create(WebApplicationType)} 方法构造出 context
             * */
            context = createApplicationContext();

在Servlet的环境下会创建AnnotationConfigServletWebServerApplicationContext。

配置应用程序上下文

            /**
             * 配置 IOC 容器:
             *  1. 给IOC容器设置上 environment
             *  2. 给IOC容器设置上 ResourceLoader、ConversionService
             *  3. 回调 ApplicationContextInitializer、SpringApplicationRunListener、bootstrapContext 方法
             *      3.1 初始化IOC容器    ApplicationContextInitializer#initialize
             *      3.2 配置IOC容器     SpringApplicationRunListener#contextPrepared
             *      3.3 完成DefaultBootstrapContext的生命周期      DefaultBootstrapContext#close
             *      3.4 IOC容器配置好了   SpringApplicationRunListener#contextLoaded
             *
             *  4. 添加单例bean:springApplicationArguments、springBootBanner
             *  5. 设置两个属性 allowCircularReferences、allowBeanDefinitionOverriding
             *  6. 添加两个BeanFactoryPostProcessor:
             *          LazyInitializationBeanFactoryPostProcessor:这个是用来判断是否需要给补全信息的 `beanDefinition.setLazyInit(true);`
             *          PropertySourceOrderingBeanFactoryPostProcessor:这个是用来将名叫 defaultProperties 的 PropertySource 移到 最后面的,也就是属性访问的优先级最低
             *  7. 将启动类添加到IOC容器中,说白了就是注册配置类
             * */
            prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);

后置处理应用上下文

SpringApplication:


    protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
        if (this.beanNameGenerator != null) {
            context.getBeanFactory()
                    .registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, this.beanNameGenerator);
        }
        if (this.resourceLoader != null) {
            if (context instanceof GenericApplicationContext) {
                ((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
            }
            if (context instanceof DefaultResourceLoader) {
                ((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
            }
        }
        if (this.addConversionService) {
            context.getBeanFactory()
                    .setConversionService(context.getEnvironment()
                            .getConversionService());
        }
    }

应用初始化器

    protected void applyInitializers(ConfigurableApplicationContext context) {
        for (ApplicationContextInitializer initializer : getInitializers()) {
            Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
                    ApplicationContextInitializer.class
            );
            Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            initializer.initialize(context);
        }
    }

上下文初始化回调

    EventPublishingRunListener:

    public void contextPrepared(ConfigurableApplicationContext context) {
        this.initialMulticaster
                .multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
    }

引导上下文关闭

public void close(ConfigurableApplicationContext applicationContext) {
        this.events.multicastEvent(new BootstrapContextClosedEvent(this, applicationContext));
    }

上下文准备回调

    public void contextLoaded(ConfigurableApplicationContext context) {
        for (ApplicationListener<?> listener : this.application.getListeners()) {
            if (listener instanceof ApplicationContextAware) {
                // 设置IOC容器
                ((ApplicationContextAware) listener).setApplicationContext(context);
            }
            // 给IOC容器 添加 listener
            context.addApplicationListener(listener);
        }
        // 发布事件
        this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
    }

刷新应用程序上下文

核心,在spring源码文章分析。

    refreshContext(context);

应用启动事件回调

    EventPublishingRunListener:

    public void started(ConfigurableApplicationContext context, Duration timeTaken) {
        context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context, timeTaken));
        AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
    }

回调Runners

    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());
        // 排序,会按照 Ordered 或者 @Order 或者 @Priority 升序排序
        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);
            }
        }
    }

应用就绪回调

    EventPublishingRunListener:

    public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
        context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context, timeTaken));
        AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
    }