ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

SpringBoot启动流程

2021-10-24 03:34:41  阅读:180  来源: 互联网

标签:SpringBoot 启动 流程 args class environment context new public


 

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

 

标签:SpringBoot,启动,流程,args,class,environment,context,new,public
来源: https://www.cnblogs.com/chenxingyang/p/15450168.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有