盘点 SpringBoot : Application 主流程

5,000 阅读9分钟

首先分享之前的所有文章 , 欢迎点赞收藏转发三连下次一定 >>>> 😜😜😜
文章合集 : 🎁 juejin.cn/post/694164…
Github : 👉 github.com/black-ant
CASE 备份 : 👉 gitee.com/antblack/ca…

一 . 前言

这一篇来说一说 SpringBoot Application 的主流程.

SpringAppliation 的主流程入口很简单 :

@SpringBootApplication
public class BaseApplication {
    public static void main(String[] args) {
        SpringApplication.run(BaseApplication.class, args);
    }
}

1 > 使用 @SpringBootApplication 注解,标明是 Spring Boot 应用。通过它,可以开启自动配置的功能。
2 > main 方法 : 调用 SpringApplication#run(Class<?>... primarySources) 方法,启动 Spring Boot 应用

我们从这个入口一步步看看 , 这个流程里面到底做了什么 , 其中主要涉及这几件事:

  • 创建且启动 listener
  • 通过 args 生成 environment
  • 通过 environment 创建 context
  • 刷新 context
  • 当然 , 还会打印 Banner

流程图

SpringBoot 流程.png

二 . 流程解析

2.1 SpringApplication 核心流程

核心流程主要在SpringApplication.class 中 ,我们从这个流程看看:

SpringApplication 属性

F- resourceLoader
    ?- 资源加载器
F- primarySources 
    ?- 主要的 Java Config 类的数组
F- webApplicationType 
    ?- 调用 WebApplicationType#deduceFromClasspath() 方法,通过 classpath ,判断 Web 应用类型。
F- listeners 
    ?- ApplicationListener 数组。
F- mainApplicationClass 
    ?- 调用 #deduceMainApplicationClass() 方法,获得是调用了哪个 #main(String[] args) 方法
    
    
// 提供了三种 ApplicationContext 加载类 , 这个后续会用上
String DEFAULT_CONTEXT_CLASS = "org.springframework.context.annotation.AnnotationConfigApplicationContext";
String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";


// 默认Banner 地址 -> "banner.txt"
String BANNER_LOCATION_PROPERTY_VALUE = SpringApplicationBannerPrinter.DEFAULT_BANNER_LOCATION;
    

SpringApplication run 方法主流程

M1_01- run()
    T-> 计时 ,创建 StopWatch  并且启动 , 用于记录启动的时长
    -> configureHeadlessProperty() : 配置 headless 属性
        ?- Headless模式是系统的一种配置模式。在该模式下,系统缺少了显示设备、键盘或鼠标
        ?- 该模式下可以创建轻量级组件 , 收集字体等前置工作
    - getRunListeners : 获取 SpringApplicationRunListeners ,并且开启监听 listeners.starting()
    - 1 创建  ApplicationArguments 对象
    - 2 prepareEnvironment 加载属性配置(传入 listener + arguments ) -> M20_01
        ?- 执行完成后,所有的 environment 的属性都会加载进来 (application.properties等)
    - 3 打印banner(printBanner) 
    - 4 创建Spring 容器(createApplicationContext)
    -   准备异常对象(getSpringFactoriesInstances.SpringBootExceptionReporter )
    - 5 调用所有初始化类的 initialize 方法(prepareContext) , 初始化Spring 容器
    - 6 刷新容器(refreshContext) , 执行 Spring 容器的初始化的后置逻辑(afterRefresh)
    T-> 计时完成    
    - 7 通知 SpringApplicationRunListener  , 执行异常处理等收尾

SpringApplication 主流程伪代码

public ConfigurableApplicationContext run(String... args) throws Exception {
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	ConfigurableApplicationContext context = null;
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
	configureHeadlessProperty();
	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting();
	try {
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
                // 调用 M1_21 获取 ConfigurableEnvironment
		ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
		configureIgnoreBeanInfo(environment);
		Banner printedBanner = printBanner(environment);
		// PS:M1_01_03
		context = createApplicationContext();
                // 从 factories 中获取 Exception M1_11
		exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
                // M1_35 : 为 Context 添加属性
		prepareContext(context, environment, listeners, applicationArguments, printedBanner);
                // M1_50 : 刷新容器Bean
		refreshContext(context);
		afterRefresh(context, applicationArguments);
                // 计时结束
		stopWatch.stop();
		if (this.logStartupInfo) {
			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
		}
		listeners.started(context);
                
                // 执行 implements ApplicationRunne 对象
		callRunners(context, applicationArguments);
	}catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, listeners);
		throw new IllegalStateException(ex);
	}
	
	try {
		listeners.running(context);
	}catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, null);
		throw new IllegalStateException(ex);
	}
	return context;
}

2.2 子模块 : Enviroment 处理

M1_21- prepareEnvironment
    - getOrCreateEnvironment -> M21_01
    - 

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
    // 内部通过 WebApplicationType 生成不同的 Environment (可以set 自己的 Environment) -> M1_23
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    // 重写此方法以完全控制环境自定义,或者重写上述方法之一以分别对属性源或概要文件进行细粒度控制。 -> M1_24
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    // 对 configurationProperties 属性进行处理 -> M2_01
    ConfigurationPropertySources.attach(environment);
    // listener 处理
    listeners.environmentPrepared(environment);
    // 将 environment 绑定到 SpringApplication
    bindToSpringApplication(environment); -> M1_25
    if (!this.isCustomEnvironment) {
        environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,deduceEnvironmentClass());
    }
    ConfigurationPropertySources.attach(environment);
    return environment;
}

M1_23- getOrCreateEnvironment
    - 通过 webApplicationType , 创建三种不同的 Environment

// M1_23 伪代码
private ConfigurableEnvironment getOrCreateEnvironment() {
    if (this.environment != null) {
        return this.environment;
    }
    switch (this.webApplicationType) {
        case SERVLET:
            return new StandardServletEnvironment();
        case REACTIVE:
            return new StandardReactiveWebEnvironment();
        default:
            return new StandardEnvironment();
    }
}


M1_24- configureEnvironment
    - 获取 ApplicationConversionService 的实现类
    - 调用 configurePropertySources(environment, args) , 在此应用程序环境中添加、删除或重新排序任何PropertySources。
        - MutablePropertySources sources = environment.getPropertySources();
            ?- 获取前面的 MutablePropertySources
	- sources.addLast : 添加 defaultProperties
	- 如果 args > 0 , 且可以添加 commonLine , 则添加CommandLineProperties
            ?- 其中会判断属性 commandLineArgs 是否会存在 ,存在则常用替换方式
            
// M1_24 伪代码
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
    if (this.addConversionService) {
        ConversionService conversionService = ApplicationConversionService.getSharedInstance();
        environment.setConversionService((ConfigurableConversionService) conversionService);
    }
    configurePropertySources(environment, args);
    configureProfiles(environment, args);
}



C2- ConfigurationPropertySources.
    M2_01- attach(environment);
	- sources = ((ConfigurableEnvironment) environment).getPropertySources() : 获取 MutablePropertySources
	- attached = sources.get(ATTACHED_PROPERTY_SOURCE_NAME) : 获取 PropertySource
        - 如果 attached 为null 或者 不等于 sources , 则将 sources 替换原先的 attached
        
// Binder : 从一个或多个容器绑定对象的容器对象
M1_25- bindToSpringApplication
C3- Binder
    M3_01- bind(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler, Context context,boolean allowRecursiveBinding, boolean create)
        - context.clearConfigurationProperty() : 清空原属性
        - handler.onStart(name, target, context) : BindHandler 开始绑定
        - bindObject : 将 属性绑定到对象
        - handleBindResult : 返回 绑定结果
   
   
private <T> T bind(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler, Context context,boolean allowRecursiveBinding, boolean create) {
    try {
        Bindable<T> replacementTarget = handler.onStart(name, target, context);
        if (replacementTarget == null) {
            return handleBindResult(name, target, handler, context, null, create);
        }
        target = replacementTarget;
        Object bound = bindObject(name, target, handler, context, allowRecursiveBinding);
        return handleBindResult(name, target, handler, context, bound, create);
    }catch (Exception ex) {
        return handleBindError(name, target, handler, context, ex);
    }
}
        

configureIgnoreBeanInfo 配置

// 其中仅设置了2个属性 : 

// 属性一 : spring.beaninfo.ignore , 用于
environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE)

// 设置二 : 设置到 System 中
System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString())

//那么该属性是为了干什么 ? -> spring.beaninfo.ignore
当值为 true 时 , 意味着跳过对 BeanInfo 类的搜索 . 
如果经历了对不存在的 BeanInfo 类的重复 ClassLoader 访问,可以考虑将这个标志切换为“ true”,以防在启动或延迟加载时这种访问开销很大

但是现阶段所有 BeanInfo 元数据类,默认值是"false"

2.3 Banner 的打印

纯粹是好奇 , 过来看一眼


M1_28- printBanner : 准备 Banner 类


// 代码详情
private Banner printBanner(ConfigurableEnvironment environment) {
    if (this.bannerMode == Banner.Mode.OFF) {
        return null;
    }
    ResourceLoader resourceLoader = (this.resourceLoader != null) 
        ? this.resourceLoader
        : new DefaultResourceLoader(getClassLoader());
        
    SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
    if (this.bannerMode == Mode.LOG) {
        return bannerPrinter.print(environment, this.mainApplicationClass, logger);
    }
    // 核心代码 -> 调用类 SpringBootBanner
    return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}

// 核心类 SpringBootBanner
C- SpringBootBanner
    M- printBanner
        - printStream.println(line) : 逐行打印那个 Spring
        - 打印版本号
            ?-  :: Spring Boot ::        (v2.3.1.RELEASE)

// ps : 点进去就知道了 , 逐行打印

  • 提供了一个开关
  • 构建一个 SpringApplicationBannerPrinter ,
  • 调用 print 生成了一个 Banner 对象

2.4 createApplicationContext 逻辑

该逻辑为创建 ApplicationContext 的相关逻辑 , 这里先简单过一下 :


C- SpringApplication
    M1_30- createApplicationContext
    	- Class<?> contextClass = this.applicationContextClass;
	    IF- contextClass为null
         	- 根据 webApplicationType 类型,获得 ApplicationContext 类型
            - AnnotationConfigServletWebServerApplicationContext 
            - AnnotationConfigApplicationContext
            - AnnotationConfigReactiveWebServerApplicationContext
         - 根据 contextClass 创建 ApplicationContext 对象   
         
         
// M1_30 伪代码
protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                 // 根据不同 webApplicationType 准备不同的 ContextClass
                switch (this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                    break;
                case REACTIVE:
                    contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                    break;
                default:
                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
                }
            }
            catch (ClassNotFoundException ex) {
                throw new IllegalStateException(
                        "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
            }
        }
        // 反射构造器方法获得 context 实现类
        return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
    }
    
    
// ApplicationContext 核心流程值得深入 , 后面开一个单章来详细是说
    

PS:M1_01_03 生成一个 ConfigurableApplicationContext data-applicationContext.jpg

PS : ApplicationContext 体系结构

ApplicationContext.png

这里补充一下 Reactive 的区别

SpringBoot-Stack.jpg

如图所示 , Reactive 是 Spring 中一个重要的技术栈 , Reactive 可以用于构建响应性、弹性、弹性和消息驱动的企业级反应系统.

WebFlux 并不是 Spring MVC 替代,它主要应用还是在异步非阻塞编程模型上 , 使用了 WebFlux 的应用,其整体响应时间更短,启动的线程数更少,使用的内存资源更少。同时,延迟越大,WebFlux 的优势越明显

具体可以参考这篇文档 @ blog.csdn.net/u010862794/…

2.5 中间操作

M1_11 获取 SpringBootExceptionReporter 的处理类

getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);


// Spring.factories
# Error Reporters
org.springframework.boot.SpringBootExceptionReporter=\
org.springframework.boot.diagnostics.FailureAnalyzers

M1_12 callRunners : 干什么

该方法主要是运行 ApplicationRunner

// callRunners 主流程
private void callRunners(ApplicationContext context, ApplicationArguments args) {
    List<Object> runners = new ArrayList<>();
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    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);
        }
    }
}


@Component
public class SourceTestLogic implements ApplicationRunner {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public void run(ApplicationArguments args) throws Exception {
        logger.info("------> run <-------");
    }
}

// 简单点说 , ApplicationRunner 初始化启动就是这里做的



2.6 Context 的三次处理

Context 的二次处理分为 三步 :

  • prepareContext(context, environment, listeners, applicationArguments, printedBanner);
    • 设置 Context 的前置属性
  • refreshContext(context);
    • 注入 Bean , 注册监听器 , 初始化并发布事件
  • afterRefresh(context, applicationArguments);
    • 现阶段为空实现

prepareContext 的主流程

// prepareContext(context, environment, listeners, applicationArguments, printedBanner);
M1_35- prepareContext : 准备 ApplicationContext 对象,主要是初始化它的一些属性
        -> 1 设置 context 的 environment 属性
        -> 2 调用 #postProcessApplicationContext(ConfigurableApplicationContext context) 方法,
            ?- 设置 context 的一些属性 -> M1_36
        -> 3 调用 #applyInitializers(ConfigurableApplicationContext context) 方法,
            ?- 初始化 ApplicationContextInitializer -> applyInitializers
        -> 4 调用 SpringApplicationRunListeners#contextPrepared
            ?- 通知 SpringApplicationRunListener 的数组,Spring 容器准备完成
        -> 5 设置 beanFactory 的属性
        -> 6 调用 #load(ApplicationContext context, Object[] sources) 方法,加载 BeanDefinition 们
            ?- 
            -> 创建 BeanDefinitionRegistry 对象
            -> 设置 loader 属性
            -> 执行BeanDefine 加载

// M1_35 伪代码
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
            SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
        //  为容器设置 environment
        context.setEnvironment(environment);
        // 设置容器 classloader 和 conversionService , 即容器中类的加载工具
        postProcessApplicationContext(context);
        // 在刷新上下文之前,将任何ApplicationContextInitializers应用于该上下文
        applyInitializers(context);
        // listeners 执行 , 在创建并准备好ApplicationContext之后调用,但在加载源之前调用。
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
             // 打印启动日志配置
            logStartupInfo(context.getParent() == null);
             // 打印 active profile 信息
            logStartupProfileInfo(context);
        }
        // Add boot specific singleton beans
        // beanFactory 注入相关Bean
        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) {
            // 添加一个新的BeanFactoryPostProcessor
            // 该新的BeanFactoryPostProcessor将在刷新之前应用于此应用程序上下文的内部Bean工厂,然后再评估任何Bean定义。 
            // 在上下文配置期间调用。
            context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
        }
        // Load the sources
        Set<Object> sources = getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        // -> M1_38
        load(context, sources.toArray(new Object[0]));
        listeners.contextLoaded(context);
}    

M1_36- postProcessApplicationContext : 在ApplicationContext中应用任何相关的后处理
	- beanNameGenerator 存在则设置到 context.getBeanFactory().registerSingleton 中
	- resourceLoader 存在且 为 GenericApplicationContext类型 , 则 setResourceLoader
	- resourceLoader 存在且 为 resourceLoader 则 setClassLoader
	- addConversionService 为 true 则设置到 BeanFactory 中
     
// M1_36 伪代码
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());
    }
}
    

M1_37- applyInitializers
    FOR-  (ApplicationContextInitializer initializer : getInitializers()) : for 循环处理 Initializers
        - Assert判断 是否为 ApplicationContextInitializer 的实例
        - initializer.initialize(context) 初始化对象
    
            
M1_38- load
    - 这里主要是创建 BeanDefinitionLoader
        
protected void load(ApplicationContext context, Object[] sources) {
    // 创建 BeanDefinitionLoader , 直接 new 的 
    BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
    if (this.beanNameGenerator != null) {
        // beanName 生成类
        loader.setBeanNameGenerator(this.beanNameGenerator);
    }
    if (this.resourceLoader != null) {
        loader.setResourceLoader(this.resourceLoader);
    }
    if (this.environment != null) {
        loader.setEnvironment(this.environment);
    }
    // -> M5_01
    loader.load();
} 

C5- BeanDefinitionLoader
    M5_01- loader
        ?- 这里会循环调用 load source
 
// M5_01 伪代码
for (Object source : this.sources) {
    count += load(source);
}   

refresh 流程


C- AbstractApplicationContext
    M1_50- refreshContext(context);
        - refresh(context);
        - 如果有 ShutdownHook (关闭钩子) , 则注册 registerShutdownHook


    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 准备此上下文以进行刷新。
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // 告诉子类刷新内部bean工厂
            prepareBeanFactory(beanFactory);

            try {
                // 允许在上下文子类中对bean工厂进行后处理
                postProcessBeanFactory(beanFactory);

                // 调用在上下文中注册为bean的工厂处理器
                // IOC 的主要逻辑就在其中
                invokeBeanFactoryPostProcessors(beanFactory);

                // 注册拦截Bean创建的Bean处理器
                registerBeanPostProcessors(beanFactory);

                // 初始化此上下文的消息源
                initMessageSource();

                // 初始化此上下文的事件多主控器.
                initApplicationEventMulticaster();

                // 初始化特定上下文子类中的其他特殊bean.
                onRefresh();

                // 检查侦听器bean并注册它们.
                registerListeners();

                // 实例化所有剩余的(非lazy-init)单例.
                finishBeanFactoryInitialization(beanFactory);

                //最后一步:发布相应的事件
                finishRefresh();
            }catch (BeansException ex) {
            
                // 销毁已创建的单件以避免资源悬空
                destroyBeans();

                // 重置“活动”标志.
                cancelRefresh(ex);

                // 将异常传播到调用方.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }
    
// 这一部分也是 AbstractApplicationContext 的主要流程 , 放在后续 ApplicationContext 单章说
    

afterRefresh 流程

PS : 这是一个空实现

M1_60- afterRefresh


2.7 Listener 处理

Application 启动时 , Listener 总共涉及到四个操作 :

  • getRunListeners
  • listener.starting
  • listener.started
  • listener.running

以我这微薄的英语水平 , 这里面怕是有个进行时和一个过去时 , 哈哈哈哈哈
可以看到 , 第一步和第四步目的都比较明确 , 主要来看看第二 . 三步

getRunListeners

C- SpringApplication
    M- getRunListeners
        - getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)
		
// 可以看到 , 从 Factories 中获取的 , 先阶段只有一个 EventPublishingRunListener
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

listener.starting

//这里的 starting 是 EventPublishingRunListener 运行
// 具体事件的处理逻辑 , 我们后续文档继续深入

C- EventPublishingRunListener
    M- starting()
        - this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
	
C- AbstractApplicationEventMulticaster
    ?- 将所有事件多播给所有注册的侦听器,并在调用线程中调用它们 , 简单点说就是事件群发
	
	
	

listeners.started(context)

// 这里的事件就更多了

for (SpringApplicationRunListener listener : this.listeners) {
    listener.started(context);
}

这里还是 EventPublishingRunListener
    
@Override
public void started(ConfigurableApplicationContext context) {
    context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
    AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
}    


listener.running

// 发布 ReadyEvent
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);

篇幅有限 , 就不详细看看哪些执行了

2.8 其他处理


	
	
private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception,
			Collection<SpringBootExceptionReporter> exceptionReporters, SpringApplicationRunListeners listeners) {
    try {
        try {
            // 处理退出码
            handleExitCode(context, exception);
            if (listeners != null) {
                listeners.failed(context, exception);
            }
        }finally {
            reportFailure(exceptionReporters, exception);
            if (context != null) {
                context.close();
            }
        }
    }catch (Exception ex) {
        logger.warn("Unable to close ApplicationContext", ex);
    }
    ReflectionUtils.rethrowRuntimeException(exception);
}
	

三 . 总结

这一篇对 SpringBoot 的大概流程简单过了一遍 , 篇幅有限有几个点暂时先没纳入 , 后续补充

  • @SpringApplication 注解
  • SpringApplicationContext 的始末
  • Listener 的加载逻辑

更新记录

  • v20210804 : 更新布局 , 优化结构