SpringBoot启动流程

 

一、SpringApplication 构造

run方法启动

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

 

构造函数做了什么

public class SpringApplication {

    public SpringApplication(Class<?>... primarySources) {
        this(null, primarySources);
    }
    
    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        // 资源加载器, 实际是null
        this.resourceLoader = resourceLoader;
        // 配置类不能位null, 一般只设置一个主配置类
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        // 判断应用类型, 暂时只用管 Servlet 应用即可
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        // 加载 META-INF/spring.factories 文件, 注意 META-INF/spring.factories 的加载是一次性加载的
        // 全部加载完毕后, 取出所有键为 BootstrapRegistryInitializer 的类
        this.bootstrapRegistryInitializers = new ArrayList<>(
                getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
        // META-INF/spring.factories 所有键为 ApplicationContextInitializer 的类, 赋值字段 initializers
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        // META-INF/spring.factories 所有键为 ApplicationListener 的类, 赋值字段 listeners
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        // main 函数所在类
        this.mainApplicationClass = deduceMainApplicationClass();
    }
}

三种 Listener

  1. BootstrapRegistryInitializer:只会被调用一次,后面可以看到,最先执行,在 BootstrapContext 创建后立即执行,这时我们平时应用中使用的 ApplicationContext 都还没有创建呢,【帮助 BootstrapContext  初始化】
  2. ApplicationContextInitializer:在 ApplicationContext 被创建,设置了 Environment 后,未 refresh 前调用,基本上可认为在 ApplicationContext 还为初始化前调用,【帮助 ApplicationContext  初始化】
  3. ApplicationListener:响应各种事件,会被 EventPublishingRunListener(SpringApplicationRunListeners) 调用
  4. SpringApplicationRunListener:【暂略】

 

二、run流程

 

 

1. BootstrapContext 创建

public class SpringApplication {

    private DefaultBootstrapContext createBootstrapContext() {
        /// 默认启动器
        DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
        // 调用所有 NETA-INF/spring.factories 下找到的 BootstrapRegistryInitializer 对象的 initialize 初始化方法
        // 传入 BootstrapRegistry 作为参数, 可以看下提高了哪些API
        this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
        return bootstrapContext;
    }
}
  1. 创建 BootstrapRegistry 实例 DefaultBootstrapContext
  2. 调用 BootstrapRegistryInitializer#initialize,参数为刚刚创建的 BootstrapRegistry 

 

2. 查找  SpringApplicationRunListener

public class SpringApplication {
    private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
        // SpringApplicationRunListeners 封装了所有 SpringApplicationRunListener 实例
        return new SpringApplicationRunListeners(logger,
                // META-INF/spring.factories 内的 SpringApplicationRunListener 并创建实例
                getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
                // SpringApplication 的, 默认是 DefaultApplicationStartup(基本啥也没干), 应该是监控埋点, 监控启动时的各种性能指标的
                // 说白了第三方可以进行扩展, 暂时略
                this.applicationStartup);
    }
}

下面看一下 SpringApplicationRunListener 的各个方法

public interface SpringApplicationRunListener {

    /**
     * 差不多当调用run方法后会立即调用,可以用于非常早期的初始化'
     * BootstrapRegistryInitializer#initialize -> starting
     */
    default void starting(ConfigurableBootstrapContext bootstrapContext) {
    }

    /**
     * Environment 环境准备好之后调用, 此时 ApplicationContext 还未创建
     */
    default void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
            ConfigurableEnvironment environment) {
    }
    
    // -- 中间 PrintBanner, 打印了 Banner

    /**
     * ApplicationContext 创建后 -> setEnvironment -> ApplicationContextInitializer#initialize -> contextPrepared
     * 这个执行完毕, BootstrapContext 就会 close 了
     */
    default void contextPrepared(ConfigurableApplicationContext context) {
    }

    /**
     * #contextPrepared -> BootstrapContext#close -> ApplicationContext#register(我们传入的主配置类) -> contextLoaded
     * 注意此时还未 refresh
     */
    default void contextLoaded(ConfigurableApplicationContext context) {
    }
    // -- 中间 ApplicationContext#refresh, 解析创建Bean实例了

    /**
     * ApplicationContext#refresh 已被调用, CommandLineRunner、ApplicationRunner 未被调用
     */
    default void started(ConfigurableApplicationContext context, Duration timeTaken) {
        started(context);
    }

    // 已废弃, 略
    @Deprecated
    default void started(ConfigurableApplicationContext context) {
    }

    /**
     * CommandLineRunner、ApplicationRunner 已被调用, run 方法马上结束
     */
    default void ready(ConfigurableApplicationContext context, Duration timeTaken) {
        running(context);
    }

    // 已废弃, 略
    @Deprecated
    default void running(ConfigurableApplicationContext context) {
    }

    /**
     * 在启动过程发生失败时调用, run 中发生异常(Throwable)被 catch 时调用, 表明启动失败
     */
    default void failed(ConfigurableApplicationContext context, Throwable exception) {
    }

}

 

 

3. 命令行参数解析

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

private static class Source extends SimpleCommandLinePropertySource {

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

public class SimpleCommandLinePropertySource extends CommandLinePropertySource<CommandLineArgs> {
    public SimpleCommandLinePropertySource(String... args) {
        super(new SimpleCommandLineArgsParser().parse(args));
    }
}

public abstract class CommandLinePropertySource<T> extends EnumerablePropertySource<T> {

    public static final String COMMAND_LINE_PROPERTY_SOURCE_NAME = "commandLineArgs";

    public static final String DEFAULT_NON_OPTION_ARGS_PROPERTY_NAME = "nonOptionArgs";

    private String nonOptionArgsPropertyName = DEFAULT_NON_OPTION_ARGS_PROPERTY_NAME;

    public CommandLinePropertySource(T source) {
        super(COMMAND_LINE_PROPERTY_SOURCE_NAME, source);
    }
}

public abstract class EnumerablePropertySource<T> extends PropertySource<T> {
    public EnumerablePropertySource(String name, T source) {
        super(name, source);
    }
}

public abstract class PropertySource<T> {

    public PropertySource(String name, T source) {
        this.name = name;
        this.source = source;
    }
}

/**
 * 解析 String数组, 这个数组一般是命令函参数
 * 解析 --开头的 类型的为 【option arguments】, 大致理解为键值对形式的
 * 其他一般的非 --开头的键值对形式的存储在另一个List中
 * 注意: IDEA 里面 VM options 里配置的是 -Dproperty=val 的被 System.getProperty 获取的属性, Program Arguments 才是命令行的
 *
 * 【注意等号两侧不能有空格, 否则作为两个参数解析(连续的是一个)】
 * 【注意下面的引号表示这是一个字符串】
 * --foo                         ---> 键foo, 值null
 * --foo                         ---> 键foo, 值 ""(空串)
 * --foo=""                      ---> 键foo, 值 ""(空串)
 * --foo=bar                     ---> 键foo, 值bar
 * --foo="bar"                   ---> 键foo, 值bar
 * --foo="bar then baz"          ---> 键foo, 值"bar then baz"
 * --foo=bar,then,baz            ---> 键foo, 值"bar then baz"
 * --foo=bar --foo=baz --foo=biz ---> 键foo, 值有三个, bar、baz、biz, List存储值的(非Set)
 *              --->
 *              --->
 *              --->
 */
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);
                }
                // 键值对象形式存储在 Map<String, List<String>> optionArgs
                commandLineArgs.addOptionArg(optionName, optionValue);
            }
            else {
                // 非键值对形式的存储在 List<String> nonOptionArgs
                commandLineArgs.addNonOptionArg(arg);
            }
        }
        return commandLineArgs;
    }

}
  1. 命令行参数形式与解析,略
  2. 应该是每一种 Property 都应该有其名称,命令行的就是 commandLineArgs

 

DefaultApplicationArguments的继承关系比较简单,继承ApplicationArguments,就是最顶层的接口了,下面列出API,就不解释了

public interface ApplicationArguments {
    // 原始未解析的数组形式的
    String[] getSourceArgs();
    Set<String> getOptionNames();
    boolean containsOption(String name);
    List<String> getOptionValues(String name);
    List<String> getNonOptionArgs();

}

但是Source的继承关系比较复杂,但还好都是单继承形式的 Source -> SimpleCommandLinePropertySource -> CommandLinePropertySource -> EnumerablePropertySource -> PropertySource

暂时略,使用到再回来

 

4. Environment 准备

    private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
            DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
        // Create and configure the environment
        // Servlet 应用创建了 ApplicationServletEnvironment 对象, 内部已经读取了 System.properties 和 System.env
        // 内部层层向上的初始化很复杂
        ConfigurableEnvironment environment = getOrCreateEnvironment();
        // getSourceArgs 得到的是未处理过的命令行参数, String[] 类型, 基本上就是main函数的 args
        // 解析命令行参数并将其作为 PropertySource 添加进入 Environment
        configureEnvironment(environment, applicationArguments.getSourceArgs());
        // 将所有PropertySource封装为一个 ConfigurationPropertySourcesPropertySource, 优先级最高, 键为 configurationProperties
        ConfigurationPropertySources.attach(environment);
        // 调用所有 SpringApplicationRunListener 的 environmentPrepared, 表示启动环境准备好了
        // SpringApplicationRunListeners 持有所有 SpringApplicationRunListener
        // 有一个 SpringApplicationRunListener 为 EventPublishingRunListener, 它(持有SpringApplication, 而 SpringApplication 在创建时又初始化并持有所有 ApplicationListener)分发各种事件给 ApplicationListener
        // 可以看一下 ApplicationListener 的API, 很简单, 只响应事件
        // 有一个 ApplicationListener 为 EnvironmentPostProcessorApplicationListener, 它只响应环境相关事件, 持有 META-INF/spring.factories 下的所有 EnvironmentPostProcessor
        // 有一个 EnvironmentPostProcessor 为 SystemEnvironmentPropertySourceEnvironmentPostProcessor, 它在 environmentPrepared 时 替换 systemEnvironment 为 OriginAwareSystemEnvironmentPropertySource, 名称不变
        // 有一个 EnvironmentPostProcessor 为 ConfigDataEnvironmentPostProcessor, 读取我们的配置文件的
        listeners.environmentPrepared(bootstrapContext, environment);
        // 移动名为 defaultProperties 的 PropertySource, 默认是没有这个 PropertySource 的
        DefaultPropertiesPropertySource.moveToEnd(environment);
        Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
                "Environment prefix cannot be set via properties.");
        // 绑定环境中spring.main开头属性绑定到SpringApplication对象中, 实际就是设置一些 SpringApplication 的属性, 比如 spring.main.xxx=log
        bindToSpringApplication(environment);
        if (!this.isCustomEnvironment) {
            environment = new EnvironmentConverter(getClassLoader())
                    // 这里实际没转
                    .convertEnvironmentIfNecessary(environment,
                    // 根据运行类型, 如Servlet的WEB
                    deduceEnvironmentClass());
        }
        // 再来一次, 保证名为 configurationProperties 的优先级最高, 且含所有 PropertySource
        ConfigurationPropertySources.attach(environment);
        return environment;
    }

 

 

 

 

getOrCreateEnvironment 先略

 

configureEnvironment 解析命令行参数加入 Environment,名称为 commandLineArgs 的命令行参数 PropertySource

    protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
        // 默认 true
        if (this.addConversionService) {
            // 转换器?干什么的
            environment.setConversionService(new ApplicationConversionService());
        }
        // 读取命令行参数(--开头的)
        configurePropertySources(environment, args);
        // 配置profile, 内部实现为空
        configureProfiles(environment, args);
    }
    protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
        // 得到 MutablePropertySources 对象
        // 四个 servletConfigInitParams 、 servletContextInitParams 、 systemProperties 、systemEnvironment
        MutablePropertySources sources = environment.getPropertySources();
        // false, defaultProperties 为null, 还未初始化
        if (!CollectionUtils.isEmpty(this.defaultProperties)) {
            DefaultPropertiesPropertySource.addOrMerge(this.defaultProperties, sources);
        }

        // addCommandLineProperties 添加命令行参数, 默认为true, 且有命令行参数才添加
        if (this.addCommandLineProperties && args.length > 0) {
            // commandLineArgs, 每个 PropertySource 都是有其名称的
            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 {
                // addFirst, 那么命令行参数的优先级显然更高, new SimpleCommandLinePropertySource 进行解析了
                // add的类型只要求是 PropertySource
                sources.addFirst(new SimpleCommandLinePropertySource(args));
            }
        }
    }

 

 

ConfigurationPropertySources.attach,PropertySource 封装

将所有 PropertySource 封装在 名为 configurationProperties 的 PropertySource 中,实际有 PropertySource 的变化必然会体现在 sources 中,而它持有 sources 引用作为 source

    public static void attach(Environment environment) {
        Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
        // 五个 命令行 > servletConfigInitParams >servletContextInitParams >systemProperties >systemEnvironment
        MutablePropertySources sources = ((ConfigurableEnvironment) environment).getPropertySources();
        // getAttached 是判断是否已经有名为 configurationProperties 这个 PropertySource, 有则获取
        PropertySource<?> attached = getAttached(sources);

        // ? 看下面创建 PropertySource 时将 sources 作为 source 了, 二次进入如果没有意外 getSource 必然和 sources 相等
        if (attached != null && attached.getSource() != sources) {
            sources.remove(ATTACHED_PROPERTY_SOURCE_NAME);
            attached = null;
        }
        if (attached == null) {
            // 封装为 ConfigurationPropertySourcesPropertySource, SpringConfigurationPropertySources 持有 sources
            // 内部暂时没有做什么解析
            sources.addFirst(new ConfigurationPropertySourcesPropertySource(ATTACHED_PROPERTY_SOURCE_NAME,
                    new SpringConfigurationPropertySources(sources)));
        }
    }

 

 

listeners.environmentPrepared(bootstrapContext, environment)

环境准备,调用 SpringApplicationRunListeners,而 SpringApplicationRunListeners 持有所有 SpringApplicationRunListener,也就是调用 所有 SpringApplicationRunListener#environmenPrepared

有一个 SpringApplicationRunListener 为 EventPublishingRunListener,它持有 SpringApplication 实例,通过这个实例间接持有所有 ApplicationListener 实例,EventPublishingRunListener 分发事件,ApplicationListener 监听事件

class SpringApplicationRunListeners {
    // SpringApplicationRunListener 的其他方法都是这样调用的, 不过是下面硬编码的字符串不同, 还有调用 listener. 的方法不同
    void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
        doWithListeners("spring.boot.application.environment-prepared",
                (listener) -> listener.environmentPrepared(bootstrapContext, environment));
    }
    
    private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction) {
        doWithListeners(stepName, listenerAction, null);
    }
    
    
    private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
            Consumer<StartupStep> stepAction) {
        // SpringApplication 创建时传过来的, 对启动过程进行监控, 默认的几乎没有实现
        StartupStep step = this.applicationStartup.start(stepName);
        // SpringApplicationRunListener 监听器执行
        this.listeners.forEach(listenerAction);
        if (stepAction != null) {
            stepAction.accept(step);
        }
        step.end();
    }
}

 

EventPublishingRunListener -> SpringApplicationRunListener

先略过它的实现,它持有 SpringApplication 实例,构造时获取了 SpringApplication 构造函数时获取的所有 ApplicationListener

内部持有一个事件分发/广播器 SimpleApplicationEventMulticaster,由它持有 SpringApplication ,并广播一个事件

环境 Environment 初始化相关

public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
            ConfigurableEnvironment environment) {
        // SimpleApplicationEventMulticaster
        this.initialMulticaster.multicastEvent(
                // 事件对象
                new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment));
    }
}

 

 

EnvironmentPostProcessorApplicationListener -> ApplicationListener

根据名称就知道是 Environment 相关的

public class EnvironmentPostProcessorApplicationListener implements SmartApplicationListener, Ordered {
    
    // 支持的事件
    public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
        // 环境准备 -> 准备好了 -> run 失败
        return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)
                || ApplicationPreparedEvent.class.isAssignableFrom(eventType)
                || ApplicationFailedEvent.class.isAssignableFrom(eventType);
    }
    
    private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
        ConfigurableEnvironment environment = event.getEnvironment();
        SpringApplication application = event.getSpringApplication();
        // getEnvironmentPostProcessors 略具体逻辑, 大致是获取 META-INF/spring.factories 的 所有 EnvironmentPostProcessor
        for (EnvironmentPostProcessor postProcessor : getEnvironmentPostProcessors(application.getResourceLoader(),
                event.getBootstrapContext())) {
            postProcessor.postProcessEnvironment(environment, application);
        }
    }
}

 

 

ConfigDataEnvironmentPostProcessor --> EnvironmentPostProcessor

加载 ConfigData 配置数据到 Environment,我们配置的东西就会被加载进去

比较复杂,略

 

 

RandomValuePropertySourceEnvironmentPostProcessor -> EnvironmentPostProcessor

随机数的

 

 

 

5. 打印 Banner

直接略

    private Banner printBanner(ConfigurableEnvironment environment) {
        // banner模式,可以是console、log、off, 默认 CONSOLE, 前一步 prepareEnvironment 有读取配置
        if (this.bannerMode == Banner.Mode.OFF) {
            return null;
        }
        ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
                : new DefaultResourceLoader(null);
        // this.banner 一般默认为 null, 好像是 fallbackBanner, 就是没有其他选择才使用这个 ?
        SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
        
        // spring.banner.image.location /(若没配置则) 类路径下 banner.gif、jpg、png
        
        // 若上面没有则 spring.banner.location / (若没配置则) 类路径下 banner.txt
        
        if (this.bannerMode == Mode.LOG) {
            return bannerPrinter.print(environment, this.mainApplicationClass, logger);
        }
        return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
    }

 

 

 

6. 创建 SpringContext 容器

public class SpringApplication {
    
    protected ConfigurableApplicationContext createApplicationContext() {
        // AnnotationConfigServletWebServerApplicationContext
        return this.applicationContextFactory.create(this.webApplicationType);
    }
    

}


public interface ApplicationContextFactory {
    ApplicationContextFactory DEFAULT = (webApplicationType) -> {
        try {
            switch (webApplicationType) {
            case SERVLET:
                // Servlet 的这个 !!!
                return new AnnotationConfigServletWebServerApplicationContext();
            case REACTIVE:
                return new AnnotationConfigReactiveWebServerApplicationContext();
            default:
                // 诶, Spring常用的这个
                return new AnnotationConfigApplicationContext();
            }
        }
    };
}


// 这里内部的初始化基本就是 Spring 中 AnnotationConfigApplicationContext 初始化的那套了, 这里就不说了
public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext
        implements AnnotationConfigRegistry {
            
    public AnnotationConfigServletWebServerApplicationContext() {
        // 内部注册的重要的 ConfigurationClassPostProcessor 
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }    
            
}

 


 

context.setApplicationStartup(this.applicationStartup);

 

 

 

7. SpringContext 容器准备

待续 .....

    private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        // 环境设置
        context.setEnvironment(environment);
        // 预处理, 实际基本啥也没做, 添加了一个 ConversionService, 暂略
        postProcessApplicationContext(context);
        // ApplicationContextInitializer#initialize 调用 !!!
        applyInitializers(context);
        // 发布上下文准备完成事件到所有监听器
        listeners.contextPrepared(context);
        // Bootstrap 环境关闭
        bootstrapContext.close(context);
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }
        // Add boot specific singleton beans
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        // 注册命令行参数Bean
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
            // 注册Banner的Bean
            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");
        // 加载Bean到上下文, 说白了就是向 SpringWeb 的 Application#register 注册所有主配置类的 BD
        load(context, sources.toArray(new Object[0]));
        // 发送上下文加载完成事件
        listeners.contextLoaded(context);
    }

 

 

8. refresh

public class SpringApplication {
    
    private void refreshContext(ConfigurableApplicationContext context) {
        // 注册钩子, 在JVM退出时执行
        if (this.registerShutdownHook) {
            // 添加:Runtime.getRuntime().addShutdownHook()
            // 移除:Runtime.getRuntime().removeShutdownHook(this.shutdownHook)
            shutdownHook.registerApplicationContext(context);
        }
        // ApplicationContext真正开始初始化容器和创建bean的阶段
        refresh(context);
    }
    
    protected void refresh(ConfigurableApplicationContext applicationContext) {
        // 这里暂略, 里面不仅有传统的 AnnotationConfigApplicationContext#refresh 的那一套
        applicationContext.refresh();
    }
    
}

 

 


 


 

protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
    // 空壳方法
}

 

 

9. ApplicationRunner 和 CommandLineRunner

public class SpringApplication {
    
    // 结束时间
    Duration timeTakeToStartup = Duration.ofNanos(System.nanoTime() - startTime);
    if (this.logStartupInfo) {
        new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakeToStartup);
    }
    // 应用程序启动事件
    listeners.started(context, timeTakeToStartup);
    // 执行实现ApplicationRunner、CommandLineRunner的run方法
    callRunners(context, applicationArguments);
    
    // ---------------------
    private void callRunners(ApplicationContext context, ApplicationArguments args) {
        List<Object> runners = new ArrayList<>();
        // ApplicationContext 中取出来的, 什么时候放入的, 待续 .......
        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);
            }
        }
    }
    
}

 

 

 

10. 完成

public class SpringApplication {
    
    catch (Throwable ex) {
        handleRunFailure(context, ex, listeners);
        throw new IllegalStateException(ex);
    }
    try {
        Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
        // 应用准备好了
        listeners.ready(context, timeTakenToReady);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, null);
        throw new IllegalStateException(ex);
    }
    return context;    
    
    // ---------------------------------------
    
    private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception,
            SpringApplicationRunListeners listeners) {
        try {
            try {
                handleExitCode(context, exception);
                if (listeners != null) {
                    // 这里 SpringApplicationRunListeners
                    listeners.failed(context, exception);
                }
            }
            finally {
                reportFailure(getExceptionReporters(context), exception);
                if (context != null) {
                    context.close();
                }
            }
        }
        catch (Exception ex) {
            logger.warn("Unable to close ApplicationContext", ex);
        }
        ReflectionUtils.rethrowRuntimeException(exception);
    }
}

 

上一篇:windows中查看端口被什么应用程序占用并删除


下一篇:Android中dp,px,sp概念梳理以及如何做到屏幕适配