zoukankan      html  css  js  c++  java
  • 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);
        }
    }
  • 相关阅读:
    常用模块——hashlib模块
    day21作业
    常用模块——configparser模块
    常用模块——xml模块
    常用模块——json模块
    常用模块——shelve模块
    常用模块——pickle模块
    shutil模块
    常用模块——os模块
    简易nagios安装出现的问题及解决方法
  • 原文地址:https://www.cnblogs.com/chenxingyang/p/15450168.html
Copyright © 2011-2022 走看看