SpringBoot event monitoring mechanism source code analysis (on) SpringBoot source code (nine)

Github address of SpringBoot Chinese Annotation Project:

github.com/yuanmabiji/…

How is the SpringApplication object constructed in this article ? SpringBoot source code (eight)

1 Learn from the past

Knowing something new, let ’s briefly review the content of the previous article. In the last article, we analyzed the construction process of the SpringApplication object and a set of SPI mechanisms implemented by SpringBoot .

  1. SpringApplicationThe construction process of the object is actually to assign values to SpringApplicationthe 6 member variables of the class ;
  2. SpringBoot implements its own SPI mechanism through the following steps:
  • 1) First get the thread context class loader;
  • 2) Then use the context class loader to load all the SPI extension implementation classes from the spring.factoriesconfiguration file and put them in the cache ;
  • 3) According to the SPI interface, remove the corresponding SPI extension implementation class from the cache;
  • 4) Instantiate and return the SPI extension implementation class taken from the cache.

2 Introduction

During the SpringBoot startup process, each different startup stage will broadcast different built-in life cycle events, and then the corresponding listener will listen to these events to perform some initialization logic work, such as ConfigFileApplicationListenerlistening to onApplicationEnvironmentPreparedEventevents to load configuration file application.propertiesenvironment variables.

Therefore, this article will analyze the source code of SpringBoot's event monitoring mechanism in the future.

3 SpringBoot broadcast built-in life cycle event process analysis

In order to explore the SpringBoot broadcast built-in life cycle event process, let us review the SpringBoot startup process code:

// SpringApplication.java

public ConfigurableApplicationContext run(String... args) {
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	ConfigurableApplicationContext context = null;
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
	configureHeadlessProperty();
	// 【0】新建一个SpringApplicationRunListeners对象用于发射SpringBoot启动过程中的生命周期事件
	SpringApplicationRunListeners listeners = getRunListeners(args);
	// 【1】》》》》》发射【ApplicationStartingEvent】事件,标志SpringApplication开始启动
	listeners.starting();
	try {
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(
				args);
		// 【2】》》》》》发射【ApplicationEnvironmentPreparedEvent】事件,此时会去加载application.properties等配置文件的环境变量,同时也有标志环境变量已经准备好的意思
		ConfigurableEnvironment environment = prepareEnvironment(listeners,
				applicationArguments);
		configureIgnoreBeanInfo(environment);
		Banner printedBanner = printBanner(environment);
		context = createApplicationContext();
		exceptionReporters = getSpringFactoriesInstances(
				SpringBootExceptionReporter.class,
				new Class[] { ConfigurableApplicationContext.class }, context); 
		// 【3】》》》》》发射【ApplicationContextInitializedEvent】事件,标志context容器被创建且已准备好
		// 【4】》》》》》发射【ApplicationPreparedEvent】事件,标志Context容器已经准备完成
		prepareContext(context, environment, listeners, applicationArguments,
				printedBanner);
		refreshContext(context);
		afterRefresh(context, applicationArguments);
		stopWatch.stop();
		if (this.logStartupInfo) {
			new StartupInfoLogger(this.mainApplicationClass)
					.logStarted(getApplicationLog(), stopWatch);
		}
		// 【5】》》》》》发射【ApplicationStartedEvent】事件,标志spring容器已经刷新,此时所有的bean实例都已经加载完毕
		listeners.started(context);
		callRunners(context, applicationArguments);
	}
	// 【6】》》》》》发射【ApplicationFailedEvent】事件,标志SpringBoot启动失败
	catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, listeners);
		throw new IllegalStateException(ex);
	}
	try {
		// 【7】》》》》》发射【ApplicationReadyEvent】事件,标志SpringApplication已经正在运行即已经成功启动,可以接收服务请求了。
		listeners.running(context);
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, null);
		throw new IllegalStateException(ex);
	}
	return context;
}
复制代码

It can be seen that SpringBoot will first create a new SpringApplicationRunListenersobject for launching various life cycle events during the SpringBoot startup process, such as launch ApplicationStartingEvent, ApplicationEnvironmentPreparedEventand ApplicationContextInitializedEventother events, and then the corresponding listener will perform some initialization logic during the SpringBoot startup process . So, when are the listeners that listen to these SpringBoot lifecycle events loaded and instantiated? Remember the analysis SpringApplicationprocess of the last article ? That's right, these listeners that perform initialization logic are loaded and instantiated in the configuration file SpringApplicationaccording to the ApplicationListenerinterface during the construction process spring.factories.

3.1 Preparing for broadcasting SpringBoot's built-in lifecycle events

3.1.1 Load ApplicationListener listener implementation class

Let's review how the SpringApplication object is constructed? SpringBoot source code (eight) article talks about this code SpringApplicationwhen constructing objects setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));.

This code do is from the spring.factoriesload in the ApplicationListenerevent listener interface SPI extended implementation class and then add to SpringApplicationthe object listenersin the collection for subsequent listening SpringBoot startup events, initialization logic to perform some work.

The specific listeners at the time of SpringBoot startup have implemented ApplicationListenerinterfaces, which are spring.factoriespartially configured as follows:

However, during debugging, the listeners are loaded from all spring.factories configuration files, and finally 10 listeners are loaded. As shown below:

3.1.2 Load SPI extension class EventPublishingRunListener

As mentioned earlier, in the startup process of SpringBoot, a new SpringApplicationRunListenersobject will be created first for launching the life cycle events in the startup process of SpringBoot. That is, let us look at SpringApplicationRunListeners listeners = getRunListeners(args);this code:

// SpringApplication.java

private SpringApplicationRunListeners getRunListeners(String[] args) {
	// 构造一个由SpringApplication.class和String[].class组成的types
	Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
	// 1) 根据SpringApplicationRunListener接口去spring.factories配置文件中加载其SPI扩展实现类
	// 2) 构建一个SpringApplicationRunListeners对象并返回
	return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
			SpringApplicationRunListener.class, types, this, args));
}

复制代码

We will focus on getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)this sentence of code. getSpringFactoriesInstancesWe are already familiar with this method. We have analyzed this method in detail in the previous article when analyzing the SPI mechanism of Spring Boot. It can be seen that SpringBoot is now loading the corresponding SPI extension implementation class according to SpringApplicationRunListenerthis SPI interface spring.factories. Let's go directly to spring.factoriessee SpringApplicationRunListenerwhich SPI implementation classes are there:

You can see from the chart, SpringApplicationRunListener only EventPublishingRunListener the SPI implementation class EventPublishingRunListener this guy is especially important during startup SpringBoot, the emission lifecycle events different SpringBoot by its different stages of the startup process in SpringBoot, that is, SpringApplicationRunListenersthe object does not assume responsibility broadcast events, In the end, EventPublishingRunListenerthe buddy was entrusted to broadcast the event.

Because from spring.factoriesthe load EventPublishingRunListenerwhen the class will instantiate the class, then we follow up EventPublishingRunListenerthe source code to see how it is to undertake emission SpringBoot life cycle events that responsibility?

// EventPublishingRunListener.java

public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {

	private final SpringApplication application;

	private final String[] args;
	/**
	 * 拥有一个SimpleApplicationEventMulticaster事件广播器来广播事件
	 */
	private final SimpleApplicationEventMulticaster initialMulticaster;

	public EventPublishingRunListener(SpringApplication application, String[] args) {
		this.application = application;
		this.args = args;
		// 新建一个事件广播器SimpleApplicationEventMulticaster对象
		this.initialMulticaster = new SimpleApplicationEventMulticaster();
		// 遍历在构造SpringApplication对象时从spring.factories配置文件中获取的事件监听器
		for (ApplicationListener<?> listener : application.getListeners()) {
			// 将从spring.factories配置文件中获取的事件监听器们添加到事件广播器initialMulticaster对象的相关集合中
			this.initialMulticaster.addApplicationListener(listener);
		}
	}

	@Override
	public int getOrder() {
		return 0;
	}
	// 》》》》》发射【ApplicationStartingEvent】事件
	@Override
	public void starting() {
		this.initialMulticaster.multicastEvent(
				new ApplicationStartingEvent(this.application, this.args));
	}
	// 》》》》》发射【ApplicationEnvironmentPreparedEvent】事件
	@Override
	public void environmentPrepared(ConfigurableEnvironment environment) {
		this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
				this.application, this.args, environment));
	}
	// 》》》》》发射【ApplicationContextInitializedEvent】事件
	@Override
	public void contextPrepared(ConfigurableApplicationContext context) {
		this.initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent(
				this.application, this.args, context));
	}
	// 》》》》》发射【ApplicationPreparedEvent】事件
	@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));
	}
	// 》》》》》发射【ApplicationStartedEvent】事件
	@Override
	public void started(ConfigurableApplicationContext context) {
		context.publishEvent(
				new ApplicationStartedEvent(this.application, this.args, context));
	}
	// 》》》》》发射【ApplicationReadyEvent】事件
	@Override
	public void running(ConfigurableApplicationContext context) {
		context.publishEvent(
				new ApplicationReadyEvent(this.application, this.args, context));
	}
	// 》》》》》发射【ApplicationFailedEvent】事件
	@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);
		}
	}
	
	// ...省略非关键代码
}

复制代码

You can see the EventPublishingRunListenerclass implements SpringApplicationRunListenerthe interface, SpringApplicationRunListenerthe interface defines the interface method of transmitting life cycle events when SpringBoot start, while the EventPublishingRunListenerclass to achieve it is through SpringApplicationRunListenerthe interface starting, environmentPreparedand contextPreparedbroadcast SpringBoot different life cycle events and so on, we look at the direct SpringApplicationRunListenerinterface to source good Off:

// SpringApplicationRunListener.java

public interface SpringApplicationRunListener {

	void starting();

	void environmentPrepared(ConfigurableEnvironment environment);

	void contextPrepared(ConfigurableApplicationContext context);

	void contextLoaded(ConfigurableApplicationContext context);

	void started(ConfigurableApplicationContext context);

	void running(ConfigurableApplicationContext context);

	void failed(ConfigurableApplicationContext context, Throwable exception);
}
复制代码

We then analyze EventPublishingRunListenerthis class, we can see that it has an important member attribute initialMulticaster, the member attribute is a SimpleApplicationEventMulticasterclass object, this class is responsible for broadcasting the life cycle events of SpringBoot startup, that isEventPublishingRunListenerSimpleApplicationEventMulticaster , the object does not assume the responsibility of broadcasting events, In the end, the buddy was entrusted to broadcast the event. EventPublishingRunListenerIt can also be seen from the source code that starting, in methods such as He environmentPreparedand so contextPreparedon, it is also by calling methods of SimpleApplicationEventMulticasterclass objects multicastEventto broadcast events.

Consider that when the event is launched during the SpringBoot startup, the event broadcaster delegates responsibilities layer by layer, which is initially SpringApplicationRunListenersassumed by the object, and then the SpringApplicationRunListenersobject delegates the responsibility of broadcasting events to the EventPublishingRunListenerobject, and finally the EventPublishingRunListenerobject delegates the responsibility of broadcasting events to the SimpleApplicationEventMulticasterobject. Why do you delegate this to layers? This is worth thinking about.

From the foregoing mentioned spring.factoriesloading out EventPublishingRunListenerwhen the class is instantiated, the instantiated bound by EventPublishingRunListenerthe constructor to be instantiated, we next analyzed the EventPublishingRunListenerconstructor source:

// EventPublishingRunListener.java

public EventPublishingRunListener(SpringApplication application, String[] args) {
	this.application = application;
	this.args = args;
	// 新建一个事件广播器SimpleApplicationEventMulticaster对象
	this.initialMulticaster = new SimpleApplicationEventMulticaster();
	// 遍历在构造SpringApplication对象时从spring.factories配置文件中获取的事件监听器
	for (ApplicationListener<?> listener : application.getListeners()) {
		// 将从spring.factories配置文件中获取的事件监听器们添加到事件广播器initialMulticaster对象的相关集合中
		this.initialMulticaster.addApplicationListener(listener);
	}
}
复制代码

It can be seen in EventPublishingRunListenerthe constructor there is a forloop iterates until the spring.factoriesload of the listeners were then added to the collection cached for later taken directly from this set out to when various events broadcast instead Then go spring.factoriesto load, improve efficiency.

3.2 Broadcast SpringBoot's built-in life cycle events

After spring.factoriesloading and instantiating the EventPublishingRunListenerobject from the configuration file, a series of SpringBoot built-in life cycle events will be launched during the SpringBoot startup process. Let us review the source code during the SpringBoot startup process:

// SpringApplication.java

public ConfigurableApplicationContext run(String... args) {
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	ConfigurableApplicationContext context = null;
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
	configureHeadlessProperty();
	// 【0】新建一个SpringApplicationRunListeners对象用于发射SpringBoot启动过程中的生命周期事件
	SpringApplicationRunListeners listeners = getRunListeners(args);
	// 【1】》》》》》发射【ApplicationStartingEvent】事件,标志SpringApplication开始启动
	listeners.starting();
	try {
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(
				args);
		// 【2】》》》》》发射【ApplicationEnvironmentPreparedEvent】事件,此时会去加载application.properties等配置文件的环境变量,同时也有标志环境变量已经准备好的意思
		ConfigurableEnvironment environment = prepareEnvironment(listeners,
				applicationArguments);
		configureIgnoreBeanInfo(environment);
		Banner printedBanner = printBanner(environment);
		context = createApplicationContext();
		exceptionReporters = getSpringFactoriesInstances(
				SpringBootExceptionReporter.class,
				new Class[] { ConfigurableApplicationContext.class }, context); 
		// 【3】》》》》》发射【ApplicationContextInitializedEvent】事件,标志context容器被创建且已准备好
		// 【4】》》》》》发射【ApplicationPreparedEvent】事件,标志Context容器已经准备完成
		prepareContext(context, environment, listeners, applicationArguments,
				printedBanner);
		refreshContext(context);
		afterRefresh(context, applicationArguments);
		stopWatch.stop();
		if (this.logStartupInfo) {
			new StartupInfoLogger(this.mainApplicationClass)
					.logStarted(getApplicationLog(), stopWatch);
		}
		// 【5】》》》》》发射【ApplicationStartedEvent】事件,标志spring容器已经刷新,此时所有的bean实例都已经加载完毕
		listeners.started(context);
		callRunners(context, applicationArguments);
	}
	// 【6】》》》》》发射【ApplicationFailedEvent】事件,标志SpringBoot启动失败
	catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, listeners);
		throw new IllegalStateException(ex);
	}
	try {
		// 【7】》》》》》发射【ApplicationReadyEvent】事件,标志SpringApplication已经正在运行即已经成功启动,可以接收服务请求了。
		listeners.running(context);
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, null);
		throw new IllegalStateException(ex);
	}
	return context;
}
复制代码

It can be seen that during the boot process of Spring Boot, a total of 7 different types of life cycle events will be emitted to mark the different boot phases of Spring Boot. At the same time, these life cycle event listeners will also perform some initialization logic during the boot process The initialization logic of these listeners will be analyzed in the next article. The following are the types of events to be emitted ApplicationFailedEventduring the SpringBoot startup process, in which an exception will be emitted during the SpringBoot startup process:

  1. ApplicationStartingEvent
  2. ApplicationEnvironmentPreparedEvent
  3. ApplicationContextInitializedEvent
  4. ApplicationPreparedEvent
  5. ApplicationStartedEvent
  6. ApplicationFailedEvent
  7. ApplicationReadyEvent

Let's take listeners.starting();this code as an example and look at EventPublishingRunListenerthe source code of the object emission event:

// SpringApplicationRunListeners.java

public void starting() {
	// 遍历listeners集合,这里实质取出的就是刚才从spring.factories中取出的SPI实现类EventPublishingRunListener
	// 而EventPublishingRunListener对象承担了SpringBoot启动过程中负责广播不同的生命周期事件
	for (SpringApplicationRunListener listener : this.listeners) {
	        // 调用EventPublishingRunListener的starting方法来广播ApplicationStartingEvent事件
		listener.starting();
	}
}
复制代码

Continue to follow listener.starting();the source code:

EventPublishingRunListener.java

// 》》》》》发射【ApplicationStartingEvent】事件
public void starting() {
	// EventPublishingRunListener对象将发布ApplicationStartingEvent这件事情委托给了initialMulticaster对象
	// 调用initialMulticaster的multicastEvent方法来发射ApplicationStartingEvent事件
	this.initialMulticaster.multicastEvent(
			new ApplicationStartingEvent(this.application, this.args));
}
复制代码

As you can see, the EventPublishingRunListenerobject ApplicationStartingEventdelegates this matter to the SimpleApplicationEventMulticasterobject initialMulticaster, and the initialMulticasterobject will eventually call its multicastEventmethods to emit ApplicationStartingEventevents. Regarding SimpleApplicationEventMulticasterhow the class broadcasts events, how has the author implemented the event monitoring mechanism in Spring? This article of Spring source code (2) has been analyzed in detail and will not be repeated here.

The source code for launching other life cycle events during the SpringBoot startup process is not analyzed here

4 Summary of SpringBoot's built-in life cycle events

Well, I have analyzed various life cycle events to be launched during the SpringBoot startup process. The following table summarizes:

5 Summary

This is the end of the source code analysis of the broadcast lifecycle events during the SpringBoot startup process. The next article will continue to introduce the listeners who listen to these lifecycle events. We review the key points in this article:

SpringBoot will launch 7 types of life cycle events during the startup process, marking different startup stages, and then the corresponding listeners will listen to these events to perform some initialization logic work.

[Source Notes] Github source code analysis project is online! ! ! The following is the Github address of the note:

github.com/yuanmabiji/…

Likes and reposts are the biggest motivation for the author!


Public number [ source notes ], focusing on the source code analysis of the Java back-end series framework.

Guess you like

Origin juejin.im/post/5e92cde8f265da47e22f1fdb