• springboot(十五) 源码分析 —— SpringApplication的run()方法


    SpringApplication的run()方法

    基于 2.2.9.RELEASE的版本,启动项目debug,当SpringApplication创建完成就开始执行#run(String... args) 方法

        public ConfigurableApplicationContext run(String... args) {

         // 1.1 创建 StopWatch 对象,并启动。StopWatch 主要用于简单统计 run 启动过程的时长。 StopWatch stopWatch
    = new StopWatch(); stopWatch.start();
    ConfigurableApplicationContext context
    = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();

         // 1.2 配置 headless 属性 configureHeadlessProperty();

    // 1.3 获得 SpringApplicationRunListener 的数组,并启动监听 SpringApplicationRunListeners listeners
    = getRunListeners(args); listeners.starting();
    try {
      // 1.4 创建  ApplicationArguments 对象 ApplicationArguments applicationArguments
    = new DefaultApplicationArguments(args);

           // 1.5 加载属性配置。执行完成后,所有的 environment 的属性都会加载进来,包括 application.properties 和外部的属性配置。 ConfigurableEnvironment environment
    = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment);

    // 1.6 打印 Spring Banner Banner printedBanner
    = printBanner(environment);

            // 1.7 创建 Spring 容器。 context
    = createApplicationContext();

           // 1.8 异常报告器 exceptionReporters
    = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context);

           // 1.9 主要是调用所有初始化类的 initialize 方法 prepareContext(context, environment, listeners, applicationArguments, printedBanner);

           // 1.10 初始化 Spring 容器。 refreshContext(context);

           // 1.11 执行 Spring 容器的初始化的后置逻辑。默认实现为空。 afterRefresh(context, applicationArguments);

           // 1.12 停止 StopWatch 统计时长 stopWatch.stop();
    if (this.logStartupInfo) {
             // 1.13 打印 Spring Boot 启动的时长日志。
    new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); }

           // 1.14 通知 SpringApplicationRunListener 的数组,Spring 容器启动完成。 listeners.started(context);

           // 1.15 调用 ApplicationRunner 或者 CommandLineRunner 的运行方法。 callRunners(context, applicationArguments); }
    catch (Throwable ex) {
           // 1.15-1 如果发生异常,则进行处理,并抛出 IllegalStateException 异常 handleRunFailure(context, ex, exceptionReporters, listeners);
    throw new IllegalStateException(ex); } try {
           // 1.16 通知 SpringApplicationRunListener 的数组,Spring 容器运行中 listeners.running(context); }
    catch (Throwable ex) {
           // 1.16-1 如果发生异常,则进行处理,并抛出 IllegalStateException 异常 handleRunFailure(context, ex, exceptionReporters,
    null); throw new IllegalStateException(ex); } return context; }

    1.1,创建 StopWatch 对象,并调用 StopWatch#run() 方法来启动。

    StopWatch 主要用于简单统计 run 启动过程的时长。

    1.2,配置 headless 属性。

    这个逻辑,可以无视,和 AWT 相关。如果不清楚AWT,可以看一看:Java的AWT简介(https://www.jianshu.com/p/9167d252657a

    1.3,调用 #getRunListeners(String[] args) 方法,获得 SpringApplicationRunListener 数组,并启动监听。

    代码如下:

        private SpringApplicationRunListeners getRunListeners(String[] args) {
            Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
         // 1.3.1   
    return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)); }

     1.3.1 SpringApplicationRunListeners  SpringApplicationRunListener 数组的封装

    SpringApplication 运行的监听器接口。

    class SpringApplicationRunListeners {
    
        private final Log log;
      
       // SpringApplicationRunListener 数组
    private final List<SpringApplicationRunListener> listeners; SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) { this.log = log; this.listeners = new ArrayList<>(listeners); } void starting() { for (SpringApplicationRunListener listener : this.listeners) { listener.starting(); } } void environmentPrepared(ConfigurableEnvironment environment) { for (SpringApplicationRunListener listener : this.listeners) { listener.environmentPrepared(environment); } } void contextPrepared(ConfigurableApplicationContext context) { for (SpringApplicationRunListener listener : this.listeners) { listener.contextPrepared(context); } } void contextLoaded(ConfigurableApplicationContext context) { for (SpringApplicationRunListener listener : this.listeners) { listener.contextLoaded(context); } } void started(ConfigurableApplicationContext context) { for (SpringApplicationRunListener listener : this.listeners) { listener.started(context); } } void running(ConfigurableApplicationContext context) { for (SpringApplicationRunListener listener : this.listeners) { listener.running(context); } } void failed(ConfigurableApplicationContext context, Throwable exception) { for (SpringApplicationRunListener listener : this.listeners) { callFailedListener(listener, context, exception); } } private void callFailedListener(SpringApplicationRunListener listener, ConfigurableApplicationContext context, Throwable exception) { try { listener.failed(context, exception); } catch (Throwable ex) { if (exception == null) { ReflectionUtils.rethrowRuntimeException(ex); } if (this.log.isDebugEnabled()) { this.log.error("Error handling failed", ex); } else { String message = ex.getMessage(); message = (message != null) ? message : "no error message"; this.log.warn("Error handling failed (" + message + ")"); } } } }

    目前,SpringApplicationRunListener 的实现类,只有 EventPublishingRunListener 类。org.springframework.boot.context.event.EventPublishingRunListener ,实现 SpringApplicationRunListener、Ordered 接口,将 SpringApplicationRunListener 监听到的事件,转换成对应的 SpringApplicationEvent 事件,发布到监听器们。

    public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
      
      // Spring 应用
    private final SpringApplication application;   
      // 参数集合
    private final String[] args;   
      // 事件广播器
    private final SimpleApplicationEventMulticaster initialMulticaster; public EventPublishingRunListener(SpringApplication application, String[] args) { this.application = application; this.args = args; this.initialMulticaster = new SimpleApplicationEventMulticaster(); for (ApplicationListener<?> listener : application.getListeners()) { this.initialMulticaster.addApplicationListener(listener); } } @Override public int getOrder() { return 0; } @Override public void starting() { this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args)); } @Override public void environmentPrepared(ConfigurableEnvironment environment) { this.initialMulticaster .multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment)); } @Override public void contextPrepared(ConfigurableApplicationContext context) { this.initialMulticaster .multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context)); } @Override public void contextLoaded(ConfigurableApplicationContext context) { for (ApplicationListener<?> listener : this.application.getListeners()) { if (listener instanceof ApplicationContextAware) { ((ApplicationContextAware) listener).setApplicationContext(context); } context.addApplicationListener(listener); } this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context)); } @Override public void started(ConfigurableApplicationContext context) { context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context)); } @Override public void running(ConfigurableApplicationContext context) { context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context)); } @Override public void failed(ConfigurableApplicationContext context, Throwable exception) { ApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception); if (context != null && context.isActive()) { // Listeners have been registered to the application context so we should // use it at this point if we can context.publishEvent(event); } else { // An inactive context may not have a multicaster so we use our multicaster to // call all of the context's listeners instead if (context instanceof AbstractApplicationContext) { for (ApplicationListener<?> listener : ((AbstractApplicationContext) context) .getApplicationListeners()) { this.initialMulticaster.addApplicationListener(listener); } } this.initialMulticaster.setErrorHandler(new LoggingErrorHandler()); this.initialMulticaster.multicastEvent(event); } } private static class LoggingErrorHandler implements ErrorHandler { private static final Log logger = LogFactory.getLog(EventPublishingRunListener.class); @Override public void handleError(Throwable throwable) { logger.warn("Error calling ApplicationEventListener", throwable); } } }

    debug listeners的值如下图

     1.4,创建  ApplicationArguments 对象。

    感兴趣的朋友可以看一看:ApplicationArguments 类(https://www.hxstrive.com/subject/spring_boot.htm?id=334

    1.5,调用 #prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) 方法,加载属性配置

    执行完成后,所有的 environment 的属性都会加载进来,包括 application.properties 和外部的属性配置。#prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) 方法,加载属性配置。

        private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
                ApplicationArguments applicationArguments) {
            // 1.5.1 创建 ConfigurableEnvironment 对象,并进行配置
            ConfigurableEnvironment environment = getOrCreateEnvironment();
            configureEnvironment(environment, applicationArguments.getSourceArgs());

         // 1.5.2 如果有 attach 到 environment 上的 MutablePropertySources ,则添加到 environment 的 PropertySource 中 ConfigurationPropertySources.attach(environment);

         // 1.5.3 通知 SpringApplicationRunListener 的数组,环境变量已经准备完成 listeners.environmentPrepared(environment);

    // 1.5.4 绑定 environment 到 SpringApplication 上 bindToSpringApplication(environment);
    if (!this.isCustomEnvironment) {
          // 1.5.5 如果非自定义 environment ,则根据条件转换 environment
    = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); }
         // 1.5.6 同1.5.2 ConfigurationPropertySources.attach(environment);
    return environment; }

    1.5.1,调用 #getOrCreateEnvironment() 方法,创建 ConfigurableEnvironment 对象

        private ConfigurableEnvironment getOrCreateEnvironment() {
        // 已经存在,则进行返回
    if (this.environment != null) { return this.environment; }

        // 不存在,则根据 webApplicationType 类型,进行创建
    switch (this.webApplicationType) { case SERVLET: return new StandardServletEnvironment(); case REACTIVE: return new StandardReactiveWebEnvironment(); default: return new StandardEnvironment(); } }

    然后调用 #configureEnvironment(ConfigurableEnvironment environment, String[] args) 方法,配置 environment 变量。代码如下:

        protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
            if (this.addConversionService) {

           // 1.5.1.1 设置 environment 的 conversionService 属性 ConversionService conversionService
    = ApplicationConversionService.getSharedInstance(); environment.setConversionService((ConfigurableConversionService) conversionService); }

         // 1.5.1.2 增加 environment 的 PropertySource 属性源 configurePropertySources(environment, args);

         // 1.5.1.3 配置 environment 的 activeProfiles 属性 configureProfiles(environment, args); }
    1.5.1.1,设置 environment 的 conversionService 属性。可以无视。感兴趣的小伙伴,可以看一看 【死磕 Spring】---- Spring 的环境属性:PropertySource、Environment、Profile(https://cloud.tencent.com/developer/article/1399708
    1.5.1.2,增加 environment 的 PropertySource 属性源

    代码如下:可以根据配置的 defaultProperties、或者 JVM 启动参数,作为附加的 PropertySource 属性源。

        protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
            MutablePropertySources sources = environment.getPropertySources();

    // 配置的 defaultProperties
    if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) { sources.addLast(new MapPropertySource("defaultProperties", this.defaultProperties)); }
         
         // 来自启动参数的
    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)); } } }
     1.5.1.3 配置 environment 的 activeProfiles 属性
        protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
            Set<String> profiles = new LinkedHashSet<>(this.additionalProfiles);
            profiles.addAll(Arrays.asList(environment.getActiveProfiles()));

         // 设置 activeProfiles environment.setActiveProfiles(StringUtils.toStringArray(profiles)); }

    对profile激活的方式感兴趣的小伙伴,可以看一看:Spring boot 激活 profile的几种方式(https://my.oschina.net/u/1469495/blog/1522784

    1.5.3,调用 SpringApplicationRunListeners#environmentPrepared(ConfigurableEnvironment environment) 方法,通知 SpringApplicationRunListener 的数组,环境变量已经准备完成。

    1.5.4,调用 #bindToSpringApplication(ConfigurableEnvironment environment) 方法,绑定 environment 到 SpringApplication 上。暂时不太知道用途。

    1.5.5,如果非自定义 environment ,则根据条件转换。默认情况下,isCustomEnvironment 为 false ,所以会执行这块逻辑。但是,一般情况下,返回的还是 environment 自身,所以可以无视这块逻辑先。

    1.5.2/1.5.6,调用 ConfigurationPropertySources#attach(Environment environment) 静态方法,如果有 attach 到 environment上的 MutablePropertySources ,则添加到 environment 的 PropertySource 中。这块逻辑,也可以先无视。

    1.6,调用 #printBanner(ConfigurableEnvironment environment) 方法,打印 Spring Banner 

    具体的代码实现,就先不分析了。 

    1.7,调用 #createApplicationContext() 方法,创建 Spring 容器

    根据 webApplicationType 类型,获得对应的 ApplicationContext 对象

        protected ConfigurableApplicationContext createApplicationContext() {
            Class<?> contextClass = this.applicationContextClass;
            if (contextClass == null) {
                try {
              // 根据 webApplicationType 类型,获得 ApplicationContext 类型
    switch (this.webApplicationType) { case SERVLET:
                // org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext contextClass
    = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS); break; case REACTIVE:
                // org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext contextClass
    = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS); break; default:
                // org.springframework.context.annotation.AnnotationConfigApplicationContext contextClass
    = Class.forName(DEFAULT_CONTEXT_CLASS); } } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex); } }
    // 创建ApplicationContext对象
    return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass); }

    1.8,通过 #getSpringFactoriesInstances(Class<T> type) 方法,进行获得 SpringBootExceptionReporter 类型的对象数组

    SpringBootExceptionReporter ,记录启动过程中的异常信息。exceptionReporters,debug结果如下: 

     

    1.9,调用 #prepareContext(...) 方法,主要是调用所有初始化类的 #initialize(...) 方法

    该方法主要是给 context 的属性做赋值,以及 ApplicationContextInitializer 的初始化。

        private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
                SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
    
            // 1.9.1  设置 context 的 environment 属性
            context.setEnvironment(environment);
            
            // 1.9.2 设置 context 的一些属性
            postProcessApplicationContext(context);
            
            // 1.9.3 初始化 ApplicationContextInitializer
            applyInitializers(context);
            
            // 1.9.4 通知 SpringApplicationRunListener 的数组,Spring 容器准备完成
            listeners.contextPrepared(context);
            
            // 1.9.5 打印日志
            if (this.logStartupInfo) {
                logStartupInfo(context.getParent() == null);
                logStartupProfileInfo(context);
            }
            
            // Add boot specific singleton beans
            // 1.9.6 设置 beanFactory 的属性
            ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
            beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
            if (printedBanner != null) {
                beanFactory.registerSingleton("springBootBanner", printedBanner);
            }
            if (beanFactory instanceof DefaultListableBeanFactory) {
                ((DefaultListableBeanFactory) beanFactory)
                        .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
            }
            if (this.lazyInitialization) {
                context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
            }
    // Load the sources // 1.9.7 加载 BeanDefinition 们 Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); load(context, sources.toArray(new Object[0]));
    // 1.9.8 通知 SpringApplicationRunListener 的数组,Spring 容器加载完成 listeners.contextLoaded(context); }

    1.9.1,设置 context 的 environment 属性

    1.9.2,调用 #postProcessApplicationContext(ConfigurableApplicationContext context) 方法,设置 context 的一些属性

        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(ApplicationConversionService.getSharedInstance());
            }
        }

    1.9.3,调用 #applyInitializers(ConfigurableApplicationContext context) 方法,遍历 ApplicationContextInitializer 数组,逐个调用 ApplicationContextInitializer#initialize(context) 方法,进行初始化。

    @SuppressWarnings({ "rawtypes", "unchecked" })
    protected void applyInitializers(ConfigurableApplicationContext context) {
    
        // 遍历 ApplicationContextInitializer 数组
        for (ApplicationContextInitializer initializer : getInitializers()) {
    
            // 校验 ApplicationContextInitializer 的泛型非空
            Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
                    ApplicationContextInitializer.class);
            Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
    
            // 初始化 ApplicationContextInitializer
            initializer.initialize(context);
        }
    }

    1.9.4,调用 SpringApplicationRunListeners#contextPrepared(ConfigurableApplicationContext context) 方法,通知 SpringApplicationRunListener 的数组,Spring 容器准备完成。

    1.9.5,打印日志。效果如下:

    2020-12-18 05:31:02.766 INFO 59714 --- [ main] com.brian.demo.DemoApplication : Starting DemoApplication on brian-System-Product-Name with PID 59714 (/home/brian/桌面/just-do-it/code/springdoc-test/target/classes started by brian in /home/brian/桌面/just-do-it/code/springdoc-test)
    2020-12-18 05:31:05.473 INFO 59714 --- [ main] com.brian.demo.DemoApplication : No active profile set, falling back to default profiles: default

    1.9.6,设置 beanFactory 的属性。

    1.9.7,调用 #load(ApplicationContext context, Object[] sources) 方法,加载 BeanDefinition 们。

    protected void load(ApplicationContext context, Object[] sources) {
        if (logger.isDebugEnabled()) {
            logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
        }
    
        // 1.9.7.1 创建 BeanDefinitionLoader 对象
        BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
    
        // 1.9.7.2 设置 loader 的属性
        if (this.beanNameGenerator != null) {
            loader.setBeanNameGenerator(this.beanNameGenerator);
        }
        if (this.resourceLoader != null) {
            loader.setResourceLoader(this.resourceLoader);
        }
        if (this.environment != null) {
            loader.setEnvironment(this.environment);
        }
    
        // 1.9.7.3 执行 BeanDefinition 加载
        loader.load();
    }
    1.9.7.1,调用 #getBeanDefinitionRegistry(ApplicationContext context) 方法,创建 BeanDefinitionRegistry 对象.
        private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) {
            if (context instanceof BeanDefinitionRegistry) {
                return (BeanDefinitionRegistry) context;
            }
            if (context instanceof AbstractApplicationContext) {
                return (BeanDefinitionRegistry) ((AbstractApplicationContext) context).getBeanFactory();
            }
            throw new IllegalStateException("Could not locate BeanDefinitionRegistry");
        }
    然后调用 #createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) 方法,创建 org.springframework.boot.BeanDefinitionLoader 对象。关于 BeanDefinitionRegistry 类,感兴趣的小伙伴,可以看一看 :【死磕 Spring】—— IoC 之 BeanDefinition 注册表:BeanDefinitionRegistry (https://blog.csdn.net/Yestar123456/article/details/103510054
    1.9.7.2,设置 loader 的属性。
    1.9.7.3,调用 BeanDefinitionLoader#load() 方法,执行 BeanDefinition 加载。关于BeanDefinition,感兴趣的小伙伴可以看一看 【死磕 Spring】—— IoC 之加载 BeanDefinition :(https://blog.csdn.net/chenssy/article/details/82494923

    1.9.8,调用 SpringApplicationRunListeners#contextLoaded(ConfigurableApplicationContext context) 方法,通知 SpringApplicationRunListener 的数组,Spring 容器加载完成。

    1.10,调用 ``#refreshContext(ConfigurableApplicationContext context)` 方法,启动(刷新) Spring 容器

    private void refreshContext(ConfigurableApplicationContext context) {
    
        // 1.10.1 开启(刷新)Spring 容器
        refresh(context);
    
        // 1.10.2 注册 ShutdownHook 钩子
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            }
            catch (AccessControlException ex) {
                // Not allowed in some environments.
            }
        }
    }

    1.10.1 处,调用 #refresh(ApplicationContext applicationContext) 方法,开启(刷新)Spring 容器

    protected void refresh(ApplicationContext applicationContext) {
    
        // 断言,判断 applicationContext 是 AbstractApplicationContext 的子类
        Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
    
        // 启动(刷新) AbstractApplicationContext
        ((AbstractApplicationContext) applicationContext).refresh();
    }

    关于AbstractApplicationContext感兴趣的小伙伴可以看一看:Spring源码分析之从refresh方法分析Spring的IoC原理 (https://blog.csdn.net/MOKEXFDGH/article/details/100731781

    1.10.2,调用 ConfigurableApplicationContext#registerShutdownHook() 方法,注册 ShutdownHook 钩子。这个钩子,主要用于 Spring 应用的关闭时,销毁相应的 Bean 们。

     1.11,调用 #afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) 方法,执行 Spring 容器的初始化的后置逻辑

    默认实现是个空方法

        protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
        }

    1.12,停止 StopWatch 统计时长

    1.13,打印 Spring Boot 启动的时长日志。效果如下:

    2020-12-17 07:09:09.382  INFO 36276 --- [           main] com.brian.demo.DemoApplication           : Started DemoApplication in 33.92 seconds (JVM running for 40.273)

    1.14,调用 SpringApplicationRunListeners#started(ConfigurableApplicationContext context) 方法,通知 SpringApplicationRunListener 的数组,Spring 容器启动完成

    1.15,调用 #callRunners(ApplicationContext context, ApplicationArguments args) 方法,调用 ApplicationRunner 或者 CommandLineRunner 的运行方法

    代码如下:

    private void callRunners(ApplicationContext context, ApplicationArguments args) {
        // 获得所有 Runner 们
        List<Object> runners = new ArrayList<>();
        runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
        runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    
        // 排序 runners
        AnnotationAwareOrderComparator.sort(runners);
        // 遍历 Runner 数组,执行逻辑
        for (Object runner : new LinkedHashSet<>(runners)) {
            if (runner instanceof ApplicationRunner) {
                callRunner((ApplicationRunner) runner, args);
            }
            if (runner instanceof CommandLineRunner) {
                callRunner((CommandLineRunner) runner, args);
            }
        }
    }

    关于callRunner方法代码如下:

        private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
            try {
                (runner).run(args);
            }
            catch (Exception ex) {
                throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
            }
        }
        private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
            try {
                (runner).run(args.getSourceArgs());
            }
            catch (Exception ex) {
                throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
            }
        }

    1.15-1,如果发生异常,则调用 #handleRunFailure(...) 方法,交给 SpringBootExceptionReporter 进行处理,并抛出 IllegalStateException 异常

    1.16,调用 SpringApplicationRunListeners#running(ConfigurableApplicationContext context) 方法,通知 SpringApplicationRunListener 的数组,Spring 容器运行中

    1.16-1,如果发生异常,则调用 #handleRunFailure(...) 方法,交给 SpringBootExceptionReporter 进行处理,并抛出 IllegalStateException 异常。

    到这里整个run方法分析就完毕了,相比Spring的启动的源码要简单些

  • 相关阅读:
    JavaScript词法结构
    【python】类变量、实例变量
    把pandas dataframe转为list方法
    list 删除一个元素的三种做法--python
    Web.config中rewite 节点引起的500.19错误
    extjs让按钮可用或者不可用
    VS2010启动奔溃
    迟来的年终总结
    Nginx配置多个server
    RestSharp的简单用法
  • 原文地址:https://www.cnblogs.com/hlkawa/p/14128656.html
Copyright © 2020-2023  润新知