Analyse du code source du mécanisme de surveillance des événements SpringBoot (activé) Code source SpringBoot (neuf)

Adresse Github du projet d'annotation chinois SpringBoot:

github.com/yuanmabiji/…

Comment l'objet SpringApplication est-il construit dans cet article ? Code source SpringBoot (huit)

1 Apprenez du passé

Connaissant l'ancien et le nouveau, examinons brièvement le contenu de l'article précédent. Dans le dernier article, nous avons analysé le processus de construction de l' objet SpringApplication et un ensemble de mécanismes SPI implémentés par SpringBoot .

  1. SpringApplicationLe processus de construction de l'objet consiste en fait à affecter des valeurs aux 6 variables membres de la SpringApplicationclasse ;
  2. SpringBoot implémente son propre mécanisme SPI à travers les étapes suivantes:
  • 1) Obtenez d'abord le chargeur de classe de contexte de thread;
  • 2) Utilisez ensuite le chargeur de classe de contexte pour charger toutes les classes d'implémentation d'extension SPI à partir du spring.factoriesfichier de configuration et les placer dans le cache ;
  • 3) Selon l'interface SPI, supprimez la classe d'implémentation d'extension SPI correspondante du cache;
  • 4) Instancier et renvoyer la classe d'implémentation d'extension SPI prise dans le cache.

2 Introduction

Pendant le processus de démarrage SpringBoot, chaque étape de démarrage diffuse différents événements de cycle de vie intégrés, puis l'écouteur correspondant écoute ces événements pour effectuer un travail de logique d'initialisation, comme l' ConfigFileApplicationListenerécoute d' onApplicationEnvironmentPreparedEventévénements pour charger application.propertiesles variables d'environnement du fichier de configuration .

Par conséquent, cet article analysera le code source du mécanisme de surveillance des événements de SpringBoot à l'avenir.

3 SpringBoot diffuse une analyse intégrée du processus d'événement du cycle de vie

Afin d'explorer le processus d'événement de cycle de vie intégré de diffusion SpringBoot, examinons le code du processus de démarrage SpringBoot:

// 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;
}
复制代码

SpringBoot sera d' abord vu d' abord dans le processus de démarrage d' un nouvel SpringApplicationRunListenersobjet est utilisé pour SpringBoot de transmission lors du démarrage de divers événements de cycle de vie, comme le lancement ApplicationStartingEvent, ApplicationEnvironmentPreparedEventet ApplicationContextInitializedEventainsi de suite, l'écouteur correspondant effectuera la logique d' initialisation lors du démarrage de certains SpringBoot . Alors, quand les écouteurs qui écoutent ces événements du cycle de vie SpringBoot sont-ils chargés et instanciés? Rappelez-vous le SpringApplicationprocessus d' analyse du dernier article ? C'est vrai, ces écouteurs qui exécutent la logique d'initialisation sont chargés et instanciés dans le fichier de configuration en SpringApplicationfonction de l' ApplicationListenerinterface pendant le processus de construction spring.factories.

3.1 Préparation de la diffusion des événements de cycle de vie intégrés de SpringBoot

3.1.1 Charger la classe d'implémentation d'écouteur ApplicationListener

Voyons comment est construit l'objet SpringApplication? L' article sur le code source (huit) de SpringBoot parle de ce code SpringApplicationlors de la construction d' objets setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));.

Ce code est do de la spring.factoriescharge dans l' ApplicationListenerécouteur d'événement interface SPI étendue classe d'implémentation, puis ajouter à SpringApplicationl'objet listenersdans la collection pour la suite des événements d' écoute de démarrage SpringBoot, la logique d'initialisation pour effectuer des travaux.

Les écouteurs spécifiques au moment du démarrage de SpringBoot ont implémenté des ApplicationListenerinterfaces, qui sont spring.factoriespartiellement configurées comme suit:

Cependant, pendant le débogage, les écouteurs sont chargés à partir de tous les fichiers de configuration spring.factories, et enfin 10 écouteurs sont chargés. Comme indiqué ci-dessous:

3.1.2 Charger la classe d'extension SPI EventPublishingRunListener

Comme mentionné précédemment, dans le processus de démarrage de SpringBoot, un nouvel SpringApplicationRunListenersobjet sera d'abord créé pour lancer les événements de cycle de vie dans le processus de démarrage de SpringBoot. Autrement dit, examinons SpringApplicationRunListeners listeners = getRunListeners(args);ce 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));
}

复制代码

Nous allons nous concentrer sur getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)cette phrase de code. getSpringFactoriesInstancesNous connaissons déjà cette méthode. Nous avons analysé cette méthode en détail dans l'article précédent lors de l'analyse du mécanisme SPI de Spring Boot. On peut voir que SpringBoot charge maintenant la classe d'implémentation d'extension SPI correspondante en fonction de SpringApplicationRunListenercette interface SPI spring.factories. Allons directement pour spring.factoriesvoir SpringApplicationRunListenerquelles classes d'implémentation SPI sont là:

Vous pouvez le voir sur le graphique, SpringApplicationRunListener seule EventPublishingRunListener la classe d'implémentation de SPI EventPublishingRunListener ce type est particulièrement important lors du démarrage SpringBoot, les événements du cycle de vie des émissions différentes SpringBoot par ses différentes étapes du processus de démarrage dans SpringBoot, qui est, SpringApplicationRunListenersl'objet ne suppose pas des événements de diffusion de la responsabilité, Finalement, EventPublishingRunListenerle copain a été chargé de diffuser l'événement.

En raison de spring.factoriesla charge EventPublishingRunListenerlorsque la classe instanciera la classe, puis nous suivons EventPublishingRunListenerle code source pour voir comment il est d'entreprendre des événements du cycle de vie de SpringBoot des émissions que la responsabilité?

// 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);
		}
	}
	
	// ...省略非关键代码
}

复制代码

Vous pouvez voir les EventPublishingRunListeneroutils de classe de SpringApplicationRunListenerl'interface, SpringApplicationRunListenerl'interface définit la méthode d'interface de transmission d' événements de cycle de vie quand SpringBoot commencer, alors que la EventPublishingRunListenerclasse pour y parvenir est par le biais de SpringApplicationRunListenerl'interface starting, environmentPreparedet les contextPreparedévénements de cycle de vie de SpringBoot de diffusion différents et ainsi de suite, nous regardons la directe SpringApplicationRunListenerinterface bonne source Éteint:

// 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);
}
复制代码

Nous analysons ensuite EventPublishingRunListenercette classe, nous pouvons voir qu'elle a un attribut membre important initialMulticaster, l'attribut membre est un SimpleApplicationEventMulticasterobjet de classe, cette classe est responsable de la diffusion des événements du cycle de vie du démarrage de SpringBoot, c'est-à-dire que l' EventPublishingRunListenerobjet n'assume pas la responsabilité de la diffusion des événements, Finalement, SimpleApplicationEventMulticasterle copain a été chargé de diffuser l'événement. EventPublishingRunListenerOn peut également voir à partir du code source que starting, dans des méthodes telles que He environmentPreparedet ainsi de contextPreparedsuite, c'est aussi en appelant des méthodes d' SimpleApplicationEventMulticasterobjets de classe multicastEventpour diffuser des événements.

Sachez que lorsque l'événement est lancé au démarrage de SpringBoot, le diffuseur d'événements délègue les responsabilités couche par couche, ce qui est initialement SpringApplicationRunListenersassumé par l' objet, puis l' SpringApplicationRunListenersobjet délègue la responsabilité de la diffusion des événements à l' EventPublishingRunListenerobjet, et enfin l' EventPublishingRunListenerobjet délègue la responsabilité de la diffusion des événements à l' SimpleApplicationEventMulticasterobjet. Pourquoi déléguez-vous cela à des calques? Cela mérite réflexion.

De ce qui précède mentionnés spring.factorieschargement hors EventPublishingRunListenerlorsque la classe est instancié, le instancié lié par EventPublishingRunListenerle constructeur à instancier, nous avons analysé ensuite la EventPublishingRunListenersource constructeur:

// 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);
	}
}
复制代码

On peut voir dans EventPublishingRunListenerle constructeur il y a une foritère en boucle jusqu'à ce que la spring.factoriescharge des auditeurs ont ensuite été ajoutés à la collection en cache pour plus tard pris directement à partir de cet ensemble sur lorsque divers événements diffusés au lieu Ensuite, passez spring.factoriesau chargement, améliorez l'efficacité.

3.2 Diffuser les événements du cycle de vie intégrés de SpringBoot

Après avoir spring.factorieschargé et instancié l' EventPublishingRunListenerobjet à partir du fichier de configuration, une série d'événements de cycle de vie intégrés SpringBoot sera lancée pendant le processus de démarrage SpringBoot. Passons en revue le code source pendant le processus de démarrage SpringBoot:

// 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;
}
复制代码

On peut voir que pendant le processus de démarrage de Spring Boot, un total de 7 types différents d'événements de cycle de vie seront émis pour marquer les différentes phases de démarrage de Spring Boot. En même temps, les écouteurs de ces événements de cycle de vie effectueront également une logique d'initialisation pendant le processus de démarrage. La logique d'initialisation de ces écouteurs sera analysée dans le prochain article. Voici les types d'événements à émettre au ApplicationFailedEventcours du processus de démarrage SpringBoot, dans lesquels une exception sera émise au cours du processus de démarrage SpringBoot:

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

Prenons listeners.starting();ce code comme exemple et regardons EventPublishingRunListenerle code source de l'événement d'émission d'objet:

// SpringApplicationRunListeners.java

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

Continuez à suivre listener.starting();le code source:

EventPublishingRunListener.java

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

Comme vous pouvez le voir, l' EventPublishingRunListenerobjet ApplicationStartingEventdélègue ce sujet à l' SimpleApplicationEventMulticasterobjet initialMulticaster, et l' initialMulticasterobjet appellera éventuellement ses multicastEventméthodes pour émettre des ApplicationStartingEventévénements. Concernant la SimpleApplicationEventMulticasterfaçon dont la classe diffuse les événements, comment l'auteur a-t-il mis en œuvre le mécanisme de surveillance des événements au printemps? Cet article du code source de Spring (2) a été analysé en détail et ne sera pas répété ici.

Le code source pour lancer d'autres événements du cycle de vie pendant le processus de démarrage SpringBoot n'est pas analysé ici

4 Résumé des événements du cycle de vie intégrés de SpringBoot

Eh bien, j'ai analysé divers événements du cycle de vie à lancer lors du démarrage de SpringBoot. Le tableau suivant résume:

5 Résumé

Ceci est la fin de l'analyse du code source des événements de cycle de vie de diffusion pendant le processus de démarrage de SpringBoot. Le prochain article continuera à présenter les écouteurs qui écoutent ces événements de cycle de vie. Nous passons en revue les points clés de cet article:

SpringBoot lancera 7 types d'événements de cycle de vie pendant le processus de démarrage, marquant différentes étapes de démarrage, puis les écouteurs correspondants écouteront ces événements pour effectuer un travail de logique d'initialisation.

[Notes de source] Le projet d'analyse de code source de Github est en ligne! ! ! Voici l'adresse Github de la note:

github.com/yuanmabiji/…

Les likes et les reposts sont la plus grande motivation de l'auteur!


Numéro public [ notes source ], se concentrant sur l'analyse du code source du framework Java back-end series.

Je suppose que tu aimes

Origine juejin.im/post/5e92cde8f265da47e22f1fdb
conseillé
Classement