Spring-boot---SpringApplication运行阶段

【Spring-boot---SpringApplication运行阶段】本文以及所有的spring-boot相关文章都是基于spring-boot 2.x版本。
所谓的运行阶段,也就是org.springframework.boot.SpringApplication#run(java.lang.String...)方法的阶段。先看一下源码

/** * Run the Spring application, creating and refreshing a new * {@link ApplicationContext}. * @param args the application arguments (usually passed from a Java main method) * @return a running {@link ApplicationContext} */ public ConfigurableApplicationContext run(String... args) { //1.计时工具 StopWatch stopWatch = new StopWatch(); //计时开始 stopWatch.start(); //声明上下文 ConfigurableApplicationContext context = null; //故障分析集合 Collection exceptionReporters = new ArrayList<>(); //2.设置headless模式 就是设置系统属性java.awt.headless configureHeadlessProperty(); //3.使用工厂方法 获取SpringApplicationRunListener 也就是springboot运行时监听 SpringApplicationRunListeners listeners = getRunListeners(args); //使用组合对象的设计模式 迭代的执行starting() listeners.starting(); try { //获取默认的应用参数 ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); //4.创建配置Environment ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); //打印Banner Banner printedBanner = printBanner(environment); //5.创建spring-boot上下文 context = createApplicationContext(); //获取启动错误报告实例 exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); //6.上下文启动之前准备并装载 prepareContext(context, environment, listeners, applicationArguments, printedBanner); //7.刷新上下文 refreshContext(context); //刷新后的上下文处理 afterRefresh(context, applicationArguments); //计时结束 stopWatch.stop(); //打印日志 if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); }//监听spring上下文,此时上下文已启动,Spring Bean已初始化完成 listeners.started(context); 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; }

大体的步骤已经在源码中添加了注释。现在需要分步理解。
1.StopWatch: 一个简单的计时器,就是记录整体spring-boot加载成功完成的时间。在运行之前声明并开始计时在上下文刷新后结束计时。
2.configureHeadlessProperty():设置headless模式---Headless模式是系统的一种配置模式。在该模式下,系统缺少了显示设备、键盘或鼠标。Headless模式虽然不是我们愿意见到的,但事实上我们却常常需要在该模式下工作,尤其是服务器端程序开发者。因为服务器(如提供Web服务的主机)往往可能缺少前述设备,但又需要使用他们提供的功能,生成相应的数据,以提供给客户端(如浏览器所在的配有相关的显示设备、键盘和鼠标的主机)。
3.加载SpringApplication运行监听(SpringApplicationRunListener):使用Spring工厂机制,加载SpringApplicationRunListener对象集合。我们可以从META-INF/spring.factories中找到其实现类(org.springframework.boot.context.event.EventPublishingRunListener)这里有一个细节,源码如下
private SpringApplicationRunListeners getRunListeners(String[] args) { Class[] types = new Class[] { SpringApplication.class, String[].class }; //生成SpringApplicationRunListenersSpringApplicationRunListener的对象集合 return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)); }

这里使用工厂机制加载SpringApplicationRunListener后,生成了 SpringApplicationRunListeners的运行监听对象集合的对象。在SpringApplicationRunListeners中我们可以看到这个类使用了组合对象的设计模式,来迭代执行SpringApplicationRunListeners的对象集合。这里只给出SpringApplicationRunListeners构造函数,从构造函数就可以看出这个类中定义了所有实现SpringApplicationRunListener接口的集合,具体的其他方法,可以自行查看源码。
SpringApplicationRunListeners(Log log, Collection listeners) { this.log = log; this.listeners = new ArrayList<>(listeners); }

额外讲一下SpringApplicationRunListener的唯一的具体实现org.springframework.boot.context.event.EventPublishingRunListener
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {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); } }

这里所有监听的事件都是使用SimpleApplicationEventMulticaster来发布的。我们再进一步看一下广播器类的源码
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {@Nullable private Executor taskExecutor; @Nullable private ErrorHandler errorHandler; @Override public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); for (final ApplicationListener listener : getApplicationListeners(event, type)) { //异步执行 Executor executor = getTaskExecutor(); if (executor != null) { executor.execute(() -> invokeListener(listener, event)); } //同步执行 else { invokeListener(listener, event); } } }

在通过广播器关联到相关的监听后,这里会异步或同步的调用监听器。
4.创建并配置ApplicationConextEnvironmentEnvironment是对配置文件(profiles )和属性文件(properties)两个关键应用环境方面的建模。提供激活和默认的配置文件和 操作底层配置资源的功能。根据SpringApplication准备阶段判断的环境类型来做配置操作。
5.创建ApplicationContext:这里通过判断当前webApplicationType的类型来加载对应的上下文。
6.上下文启动之前准备并装载(prepareContext),可以看源码中给出的注释:
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { //设置上下文 context.setEnvironment(environment); //注册单例Bean以及资源加载策略(ResourceLoader) postProcessApplicationContext(context); //初始化所有实现ApplicationContextInitializer 接口的上下文 applyInitializers(context); //发布上下文准备事件 listeners.contextPrepared(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); }// Add boot specific singleton beans context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { context.getBeanFactory().registerSingleton("springBootBanner", printedBanner); }// Load the sources Set sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); //初始化Bean 完成Bean的加载 load(context, sources.toArray(new Object[0])); //发布上下文装载事件 listeners.contextLoaded(context); }
7.刷新上下文refreshContext(context):这里只是一个引用方法具体方法在org.springframework.context.support.AbstractApplicationContext#refresh方法中,由于刷新阶段需要做很多操作,看注释就可以看明白大体步骤,具体细节可以自己看源码再结合其他前辈的博文理解。
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); }catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); }// Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; }finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }

总结 SpringApplication运行阶段主要就分为:
  • 加载:SpringApplication运行监听器(SpringApplicationRunListener)
  • 运行:SpringApplication运行监听器(SpringApplicationRunListeners)
  • 监听:Spring-boot事件,spring事件。
  • 创建:创建上下文,Environment,其他。
  • 失败:打印故障分析报告。
  • 回调。
最后附上监听和事件列表

Spring-boot---SpringApplication运行阶段
文章图片
监听.png Spring-boot---SpringApplication运行阶段
文章图片
事件.png

    推荐阅读