SpringBoot(四)SpringApplication启动类运行阶段 - SpringApplicationRunListener

前言

        最近在学习Spring Boot相关的课程,过程中以笔记的形式记录下来,方便以后回忆,同时也在这里和大家探讨探讨,文章中有漏的或者有补充的、错误的都希望大家能够及时提出来,本人在此先谢谢了!

开始之前呢,希望大家带着几个问题去学习:
1、Spring Boot SpringApplication 是什么?
2、整体流程或结构是怎样的?
3、重点内容或者核心部分是什么?
4、怎么实现的?
5、是怎么和 Spring 关联起来的?
这是对自我的提问,我认为带着问题去学习,是一种更好的学习方式,有利于加深理解。好了,接下来进入主题。

1、起源

        上篇文章我们讲了 SpringApplication 的准备阶段,在这个阶段,完成了运行时所需要准备的资源,如:initializerslisteners等。而这篇文章我们就来讲讲 SpringApplication 的运行阶段,在这个阶段,它是如何启动 Spring 应用上下文的,且如何与 Spring 事件结合起来,形成完整的 SpringApplication 生命周期的。

注:本篇文章所用到的 Spring Boot版本是 2.1.6.BUILD-SNAPSHOT

2、SpringApplication 运行阶段

        上篇文章我们讲了 SpringApplication 的构造方法,这里我们就来讲讲 SpringApplication 的核心,也就是run方法,代码如下:

public class SpringApplication {

    ...
        
    public ConfigurableApplicationContext run(String... args) {
    	// 这是 Spring 的一个计时器,计算代码的执行时间(ms级别)
    	StopWatch stopWatch = new StopWatch();
    	stopWatch.start();
    	
    	// 这俩变量在后面赋值处进行说明
    	ConfigurableApplicationContext context = null;
    	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    	
    	// 用来设置java.awt.headless属性值
    	configureHeadlessProperty();
    	
    	// 该对象属于组合模式的实现,核心是内部关联的 SpringApplicationRunListener 集合,SpringApplicationRunListener 是 Spring Boot 的运行时监听器
    	SpringApplicationRunListeners listeners = getRunListeners(args);
    	// 会在不同的阶段调用对应的方法,这里表示启动run方法被调用
    	listeners.starting();
    	
    	try {
    	
    	    // 用来获取 SpringApplication.run(args)传入的参数
    		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
    		
    		// 获取 properties 配置文件
    		ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
    		
    		// 设置 spring.beaninfo.ignore 的属性值,判断是否跳过搜索BeanInfo类
    		configureIgnoreBeanInfo(environment);
    		
    		// 这里是项目启动时,控制台打印的 Banner
    		Banner printedBanner = printBanner(environment);
    		
    		// 这里就是创建 Spring 应用上下文
    		context = createApplicationContext();
    		
    		// 获取 spring.factories 中key为 SpringBootExceptionReporter 的类名集合
    		exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
    				new Class[] { ConfigurableApplicationContext.class }, context);
    				
    		// 这里是准备 Spring 应用上下文
    		prepareContext(context, environment, listeners, applicationArguments, printedBanner);
    		
    		// 这里是启动 Spring 应用上下文,底层调用的是 ApplicationContext 的 refresh() 方法,到这里就正式进入了 Spring 的生命周期,同时,SpringBoot的自动装配特性也随之启动
    		refreshContext(context);
    		
    		// 里面是空的,猜测应该是交由开发人员自行扩展
    		afterRefresh(context, applicationArguments);
    		stopWatch.stop();
    		
    		// 这里打印启动信息
    		if (this.logStartupInfo) {
    			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
    		}
    		
    		// ApplicationContext 启动时,调用该方法
    		listeners.started(context);
    		
    		// 项目启动后,做的一些操作,开发人员可自行扩展
    		callRunners(context, applicationArguments);
    	}
    	catch (Throwable ex) {
    		handleRunFailure(context, ex, exceptionReporters, listeners);
    		throw new IllegalStateException(ex);
    	}
    
    	try {
    	
    	    // ApplicationContext 启动完成时,调用该方法
    		listeners.running(context);
    	}
    	catch (Throwable ex) {
    		handleRunFailure(context, ex, exceptionReporters, null);
    		throw new IllegalStateException(ex);
    	}
    	return context;
    }
    
    ...
}

上面就是整个过程的概览,可以看到,在运行阶段执行的操作比较多,虽然看起来杂乱无章,但其实还是有规律可循的。比如,执行的 SpringApplicationRunListeners 中的阶段方法,刚启动阶段的 starting 、已启动阶段的 started 、启动完成阶段的 running 等。还有对应的 Spring 应用上下文的创建、准备、启动操作等。接下来,就对里面的几个核心对象进行讨论。

2.1 SpringApplicationRunListeners 结构

我们先来看看 SpringApplicationRunListeners 对象,从代码可以看出该对象是由 getRunListeners 方法创建的:

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

可以看到,通过传入的 getSpringFactoriesInstances 方法的返回值,执行 SpringApplicationRunListeners 的构造方法,进行对象的创建。接着看 getSpringFactoriesInstances 方法:

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
	ClassLoader classLoader = getClassLoader();
	// Use names and ensure unique to protect against duplicates
	Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
	List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
	AnnotationAwareOrderComparator.sort(instances);
	return instances;
}

看到这大家应该比较熟悉了,通过前面几篇文章的讨论我们知道,该方法通过 SpringFactoriesLoader.loadFactoryNames 返回所有 classpass 下的 spring.factories 文件中 key 为 SpringApplicationRunListener 的实现类集合。如 Spring Boot 的内建实现:

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

最后,就是将该集合传入 SpringApplicationRunListeners 的构造方法:

class SpringApplicationRunListeners {

    ...

	private final List<SpringApplicationRunListener> listeners;

	SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
		this.log = log;
		this.listeners = new ArrayList<>(listeners);
	}

	public void starting() {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.starting();
		}
	}

	...

}

里面是将集合赋值到 listeners 属性,可以看到 SpringApplicationRunListeners 属于组合模式的实现,核心其实是内部关联的 SpringApplicationRunListener 对象集合,当外部调用该阶段方法时,就会迭代执行集合中 SpringApplicationRunListener 对应的方法。所以接下来我们就来讨论 SpringApplicationRunListener

2.1.1 SpringApplicationRunListener 事件和监听机制

SpringApplicationRunListener 负责在 SpringBoot 的不同阶段广播相应的事件,然后调用实际的 ApplicationListener 类,在该类的 onApplicationEvent 方法中,根据不同的 Spring Boot 事件执行相应操作。整个过程大概如此,接下来进行详细讨论,先来看看 SpringApplicationRunListener 定义:

public interface SpringApplicationRunListener {

    // 在run()方法开始执行时被调用,表示应用刚刚启动,对应的 Spring Boot 事件为 ApplicationStartingEvent
	void starting();

    // ConfigurableEnvironment 构建完成时调用,对应的 Spring Boot 事件为 ApplicationEnvironmentPreparedEvent
	void environmentPrepared(ConfigurableEnvironment environment);

    // ApplicationContext 构建完成时调用,对应的 Spring Boot 事件为 ApplicationContextInitializedEvent
	void contextPrepared(ConfigurableApplicationContext context);

    // ApplicationContext 完成加载但还未启动时调用,对应的 Spring Boot 事件为 ApplicationPreparedEvent
	void contextLoaded(ConfigurableApplicationContext context);

    // ApplicationContext 已启动,但 callRunners 还未执行时调用,对应的 Spring Boot 事件为 ApplicationStartedEvent
	void started(ConfigurableApplicationContext context);

    // ApplicationContext 启动完毕被调用,对应的 Spring Boot 事件为 ApplicationReadyEvent
	void running(ConfigurableApplicationContext context);

    // 应用出错时被调用,对应的 Spring Boot 事件为 ApplicationFailedEvent
	void failed(ConfigurableApplicationContext context, Throwable exception);

}

我们来看看它的实现类,也就是上面加载的 spring.factories 文件中的 EventPublishingRunListener 类,该类也是 Spring Boot 内建的唯一实现类,具体广播事件的操作在该类中进行,代码如下:

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

	@Override
	public void starting() {
		this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
	}

	...

}

可以看到,通过构造方法创建 EventPublishingRunListener 实例的过程中,调用了 getListeners 方法,将 SpringApplication 中所有 ApplicationListener 监听器关联到了 initialMulticaster 属性中。没错,这里的 ApplicationListener 监听器就是上篇文章中在 SpringApplication 准备阶段从 spring.factories 文件加载的 key 为 ApplicationListener 的实现类集合,该实现类集合全部重写了 onApplicationEvent 方法。

2.1.2 SimpleApplicationEventMulticaster 广播器

这里又引出了另一个类, 也就是 SimpleApplicationEventMulticaster ,该类是 Spring 的事件广播器,也就是通过它来广播各种事件。接着,当外部迭代的执行到 EventPublishingRunListenerstarting 方法时,会通过 SimpleApplicationEventMulticastermulticastEvent 方法进行事件的广播,这里广播的是 ApplicationStartingEvent 事件,我们进入 multicastEvent 方法:

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

    ...
    
    @Override
	public void multicastEvent(ApplicationEvent event) {
		multicastEvent(event, resolveDefaultEventType(event));
	}

	@Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		Executor executor = getTaskExecutor();
		for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				invokeListener(listener, event);
			}
		}
	}
}

通过 getApplicationListeners 方法,根据事件类型返回从上面关联的 ApplicationListener 集合中筛选出匹配的 ApplicationListener 集合,根据 Spring Boot 版本的不同,在这个阶段获取到的监听器也有可能不同,如 2.1.6.BUILD-SNAPSHOT 版本返回的是:
image

然后依次遍历这些监听器,同步或异步的调用 invokeListener 方法:

protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
		ErrorHandler errorHandler = getErrorHandler();
	if (errorHandler != null) {
		try {
			doInvokeListener(listener, event);
		}
		catch (Throwable err) {
			errorHandler.handleError(err);
		}
	}
	else {
		doInvokeListener(listener, event);
	}
}

...

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			listener.onApplicationEvent(event);
		}
		catch (ClassCastException ex) {
			String msg = ex.getMessage();
			if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
				// Possibly a lambda-defined listener which we could not resolve the generic event type for
				// -> let's suppress the exception and just log a debug message.
				Log logger = LogFactory.getLog(getClass());
				if (logger.isTraceEnabled()) {
					logger.trace("Non-matching event type for listener: " + listener, ex);
				}
			}
			else {
				throw ex;
			}
		}
	}

可以看到,最终调用的是 doInvokeListener 方法,在该方法中执行了 ApplicationListeneronApplicationEvent 方法,入参为广播的事件对象。我们就拿其中一个的监听器来看看 onApplicationEvent 中的实现,如 BackgroundPreinitializer 类:

public class BackgroundPreinitializer implements ApplicationListener<SpringApplicationEvent> {

	...
	
	@Override
	public void onApplicationEvent(SpringApplicationEvent event) {
		if (!Boolean.getBoolean(IGNORE_BACKGROUNDPREINITIALIZER_PROPERTY_NAME)
				&& event instanceof ApplicationStartingEvent && preinitializationStarted.compareAndSet(false, true)) {
			performPreinitialization();
		}
		if ((event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent)
				&& preinitializationStarted.get()) {
			try {
				preinitializationComplete.await();
			}
			catch (InterruptedException ex) {
				Thread.currentThread().interrupt();
			}
		}
	}
	
	...
}

在该方法中,通过 instanceof 判断事件的类型,从而进行相应的操作。该监听器主要的操作是新建一个后台线程去执行那些耗时的初始化工作,包括验证器、消息转换器等。LoggingApplicationListener 监听器则是对 Spring Boot 的日志系统做一些初始化的前置操作。另外两个监听器在该阶段无任何操作。

至此,SpringBoot 事件机制的整体流程大概如此,我们简要回顾一下几个核心组件:

  • SpringApplicationRunListeners:首先,在 run 方法的执行过程中,通过该类在 SpringBoot 不同的阶段调用不同的阶段方法,如在刚启动阶段调用的 starting 方法。

  • SpringApplicationRunListener:而 SpringApplicationRunListeners 属于组合模式的实现,它里面关联了 SpringApplicationRunListener 实现类集合,当外部调用阶段方法时,会迭代执行该集合中的阶段方法。实现类集合是 spring.factories 文件中定义好的类。这里是一个扩展点,详细的后面述说。

  • EventPublishingRunListener:该类是 Spring Boot 内置的 SpringApplicationRunListener 唯一实现类,所以,当外部调用各阶段的方法时,真正执行的是该类中的方法。

  • SimpleApplicationEventMulticaster:在阶段方法中,会通过 SpringSimpleApplicationEventMulticaster 事件广播器,广播各个阶段对应的事件,如这里的 starting 方法广播的事件是 ApplicationStartingEvent

  • ApplicationListener:最后 ApplicationListener 的实现类也就是 Spring Boot 监听器会监听到广播的事件,根据不同的事件,进行相应的操作。这里的 Spring Boot 监听器是也是在 spring.factories 中定义好的,这里我们也可自行扩展。

到这里 Spring Boot 事件监听机制差不多就结束了,值得注意的是 Spring Boot 监听器实现的是 SpringApplicationListener 类,事件类最终继承的也是 SpringApplicationEvent 类,所以,Spring Boot 的事件和监听机制都基于 Spring 而实现的。

2.2 ApplicationArguments 加载启动参数

        当执行完 listeners.starting 方法后,接着进入构造 ApplicationArguments 阶段:

public class SpringApplication {

    ...
    
    public ConfigurableApplicationContext run(String... args) {
		
		...
		
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			
			...
		}
	}
	
	...
}

该类是用于简化 Spring Boot 应用启动参数的封装接口,我们启动项目时输入的命令参数会封装在该类中。一种是通过 IDEA 输入的参数,如下:
image

另一种是 springboot jar包运行时传递的参数:cmd中运行java -jar xxx.jar name=张三 pwa=123

然后,可以通过 @Autowired 注入 ApplicationArguments 的方式进行使用:

public class Test {

    @Autowired
    private ApplicationArguments applicationArguments;

    public void getArgs() {
        // 获取 args 中的所有 non option 参数
		applicationArguments.getNonOptionArgs();

		// 获取 args 中所有的 option 参数的 name
		applicationArguments.getOptionNames();

		// 获取传递给应用程序的原始未处理参数
		applicationArguments.getSourceArgs();

		// 获取 args 中指定 name 的 option 参数的值
		applicationArguments.getOptionValues("nmae");

		// 判断从参数中解析的 option 参数是否包含指定名称的选项
		applicationArguments.containsOption("name");
    }
}

2.3 ConfigurableEnvironment 加载外部化配置

        接着进入构造 ConfigurableEnvironment 的阶段,该类是用来处理我们外部化配置的,如 propertiesYAML 等,提供对配置文件的基础操作。当然,它能处理的外部配置可不仅仅如此,详细的在下篇文章讨论,这里我们进行简要了解即可,进入创建该类的 prepareEnvironment 方法:

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
	// Create and configure the environment
	ConfigurableEnvironment environment = getOrCreateEnvironment();
	configureEnvironment(environment, applicationArguments.getSourceArgs());
	listeners.environmentPrepared(environment);
	bindToSpringApplication(environment);
	if (!this.isCustomEnvironment) {
		environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
				deduceEnvironmentClass());
	}
	ConfigurationPropertySources.attach(environment);
	return environment;
}

这里通过 getOrCreateEnvironment 方法返回具体的 Environment

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

可以看到,这里通过 webApplicationType 属性来判断当前应用的类型,有 ServletReactive 、 非Web 3种类型,该属性也是在上篇文章中 SpringApplication 准备阶段确定的,这里我们通常都是 Servlet 类型,返回的是 StandardServletEnvironment 实例。

之后,还调用了 SpringApplicationRunListenersenvironmentPrepared 阶段方法,表示 ConfigurableEnvironment 构建完成,同时向 Spring Boot 监听器发布 ApplicationEnvironmentPreparedEvent 事件。监听该事件的监听器有:
image

2.4 ConfigurableApplicationContext 创建 Spring 应用上下文

        这里通过 createApplicationContext 方法创建 Spring 应用上下文,实际上 Spring 的应用上下文才是驱动 Spring Boot 的核心引擎:

public class SpringApplication {

    ...

    public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
			+ "annotation.AnnotationConfigApplicationContext";

    public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
			+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";

    public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
			+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";

    ...

    protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				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);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}
	
	...
}

这里也是通过 webApplicationType 属性来确定应用类型从而创建 String 上下文,上篇文章说到该属性值是在 Spring Boot 准备阶段推导出来的。这里我们的应用类型是 Servlet ,所以创建的是 AnnotationConfigServletWebServerApplicationContext 对象。创建完 Spring 应用上下文之后,执行 prepareContext 方法进入准备上下文阶段:

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
	context.setEnvironment(environment);
	postProcessApplicationContext(context);
	applyInitializers(context);
	listeners.contextPrepared(context);
	if (this.logStartupInfo) {
		logStartupInfo(context.getParent() == null);
		logStartupProfileInfo(context);
	}
	// Add boot specific singleton beans
	ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
	beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
	if (printedBanner != null) {
		beanFactory.registerSingleton("springBootBanner", printedBanner);
	}
	if (beanFactory instanceof DefaultListableBeanFactory) {
		((DefaultListableBeanFactory) beanFactory)
				.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
	}
	// Load the sources
	Set<Object> sources = getAllSources();
	Assert.notEmpty(sources, "Sources must not be empty");
	load(context, sources.toArray(new Object[0]));
	listeners.contextLoaded(context);
}

我们来看看主要做了哪些操作:

  1. 设置了 Spring 应用上下文的 ApplicationArguments,上面说过是处理外部化配置的,具体类型为 StandardServletEnvironment

  2. Spring 应用上下文后置处理,主要是覆盖当前 Spring 应用上下文默认所关联的 ResourceLoaderClassLoader

  3. 执行 Spring 的初始化器,上篇文章说过在 Spring Boot 准备阶段初始化了一批在 spring.factories 文件中定义好的 ApplicationContextInitializer ,这里就是执行它们的 initialize 方法,同时这里也是一个扩展点,后面详细讨论。

  4. 执行 SpringApplicationRunListenerscontextPrepared 阶段方法,表示 ApplicationContext 准备完成,同时向 Spring Boot 监听器发布 ApplicationContextInitializedEvent 事件 。

  5. springApplicationArgumentsspringBootBanner 注册为 Bean

  6. 加载 Spring 应用上下文的配置源,也是在上篇文章 Spring Boot 准备阶段获取的 primarySourcessourcesprimarySources 来源于 SpringApplication 构造器参数,sources 则来源于自定义配置的 setSources 方法。

  7. 最后执行 SpringApplicationRunListenerscontextLoaded 阶段方法,表示 ApplicationContext 完成加载但还未启动,同时向 Spring Boot 监听器发布 ApplicationPreparedEvent 事件 。

接下来就是真正启动阶段,执行的是 refreshContext 方法:

private void refreshContext(ConfigurableApplicationContext context) {
    refresh(context);
	if (this.registerShutdownHook) {
		try {
			context.registerShutdownHook();
		}
		catch (AccessControlException ex) {
			// Not allowed in some environments.
		}
	}
}
protected void refresh(ApplicationContext applicationContext) {
		Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
	((AbstractApplicationContext) applicationContext).refresh();
}

可以看到,底层调用的是 AbstractApplicationContextrefresh 方法,到这里 Spring 应用正式启动,Spring Boot 核心特性也随之启动,如自动装配。随后执行 SpringApplicationRunListenersstarted 阶段方法,表示 ApplicationContext 已启动,同时向 Spring Boot 监听器发布 ApplicationStartedEvent 事件 。但还未启动完成,后面还有一个 callRunners 方法,一般来讲,里面执行一些我们自定义的操作。之后 Spring 应用才算启动完成,随后调用 running 方法,发布 ApplicationReadyEvent 事件。至此,SpringApplication 运行阶段结束。

3、总结

        最后来对 SpringApplication 运行阶段做一个总结。这个阶段核心还是以启动 Spring 应用上下文为主,同时根据应用类型来初始化不同的上下文对象,但这些对象的基类都是 Spring ConfigurableApplicationContext 类。且在启动的各个阶段中,使用 SpringApplicationRunListeners 进行事件广播,回调 Spring Boot 的监听器。同时还初始化了 ApplicationArgumentsConfigurableEnvironment 等几个组件。下篇文章我们就来讨论 Spring Boot 的外部化配置部分,来看看为什么外部的各个组件,如 RedisDubbo 等在 properties 文件中进行相应配置后,就可以正常使用。

以上就是本章的内容,如过文章中有错误或者需要补充的请及时提出,本人感激不尽。



参考:

《Spring Boot 编程思想》
https://www.cnblogs.com/youzhibing/p/9603119.html
https://www.jianshu.com/p/b86a7c8b3442
https://www.cnblogs.com/duanxz/p/11243271.html
https://www.jianshu.com/p/7a674c59d76e

posted @ 2019-12-08 19:34  龙四丶  阅读(2428)  评论(0编辑  收藏  举报