Анализ исходного кода механизма мониторинга событий SpringBoot (1) Исходный код SpringBoot (9)

Spring Boot
Анализ исходного кода механизма мониторинга событий SpringBoot (1) Исходный код SpringBoot (9)

Адрес Github китайского аннотационного проекта SpringBoot:

GitHub.com/Примечания к источнику/…

Эта статья продолжаетКак устроен объект SpringApplication? Исходный код SpringBoot (8)

1 Уроки прошлого

Ознакомившись со старым и узнав новое, давайте вкратце повторим содержание предыдущей статьи.В предыдущей статье мы разобралиПроцесс построения объекта SpringApplication и набор механизмов SPI, реализованных самим SpringBoot, ключевые шаги теперь сжаты и обобщены:

  1. SpringApplicationПроцесс строительства объекта фактически заключается в том, чтобы датьSpringApplicationКатегория6присвоение переменных-членов;
  2. SpringBoot реализует собственный механизм SPI с помощью следующих шагов:
  • 1) Сначала получите загрузчик класса контекста потока;
  • 2) Затем используйте загрузчик класса контекста изspring.factoriesв файле конфигурацииЗагрузите все классы реализации расширения SPI и поместите их в кеш.;
  • 3) Извлечь из кэша соответствующий класс реализации расширения SPI в соответствии с интерфейсом SPI;
  • 4) Создать экземпляр класса реализации расширения SPI, извлеченного из кэша, и вернуться.

2 Введение

В процессе запуска SpringBoot каждая отдельная фаза запуска будет транслировать разные встроенные события жизненного цикла, а затем соответствующие слушатели будут прослушивать эти события для выполнения некоторой логической работы по инициализации, такой какConfigFileApplicationListenerбудет контролироватьonApplicationEnvironmentPreparedEventсобытие для загрузки файла конфигурацииapplication.propertiesпеременные окружения и т.д.

Поэтому в этой статье в будущем будет проанализирован исходный код механизма мониторинга событий SpringBoot.

3 SpringBoot транслирует встроенный анализ потока событий жизненного цикла

Чтобы изучить встроенный процесс событий жизненного цикла широковещательной передачи SpringBoot, давайте рассмотрим код процесса запуска 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 сначала создаст новый во время процесса запуска.SpringApplicationRunListenersОбъект используется для генерации различных событий жизненного цикла во время процесса запуска SpringBoot, таких как запускApplicationStartingEvent,ApplicationEnvironmentPreparedEventиApplicationContextInitializedEventДождитесь события, а затем соответствующий слушатель выполнит некоторую логику инициализации во время процесса запуска SpringBoot. Итак, когда загружаются и создаются прослушиватели, которые прослушивают эти события жизненного цикла SpringBoot? Помните, что последняя статья была анализомSpringApplicationпроцесс сборки? Правильно, эти слушатели, выполняющие логику инициализации, точноSpringApplicationв процессе сборки согласноApplicationListenerинтерфейс идтиspring.factoriesЗагружается и создается в файле конфигурации.

3.1 Подготовка к трансляции встроенных событий жизненного цикла SpringBoot

3.1.1 Загрузить класс реализации прослушивателя ApplicationListener

Давайте рассмотримКак устроен объект SpringApplication? Исходный код SpringBoot (8)В статье рассказывается о строительствеSpringApplicationобъектsetListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));этот код.

Что делает этот код, так это запускspring.factoriesвыгрузитьApplicationListenerЗатем добавляется класс реализации расширения SPI интерфейса прослушивателя событий.SpringApplicationобъектlistenersВ коллекции он используется для последующего мониторинга событий в процессе запуска SpringBoot для выполнения некоторой логической работы по инициализации.

Реализованы специальные слушатели при запуске SpringBoot.ApplicationListenerинтерфейс, который находится вspring.factoriesЧасть конфигурации выглядит следующим образом:

Однако при отладке прослушиватели загружаются из всех файлов конфигурации spring.factories, и, наконец, загружаются 10 прослушивателей. Как показано ниже:

3.1.2 Загрузите класс расширения SPI EventPublishingRunListener

Как упоминалось ранее, в процессе запуска SpringBoot сначала будет создан новый.SpringApplicationRunListenersОбъект используется для эмитирования событий жизненного цикла в процессе запуска SpringBoot, то есть давайте посмотрим на него сейчасSpringApplicationRunListeners listeners = getRunListeners(args);Этот код:

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

Мы сосредоточимся наgetSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)этот код,getSpringFactoriesInstancesМы уже знакомы с этим методом, и мы уже подробно разбирали этот метод, когда анализировали механизм SpringBoot SPI в предыдущей статье. Вы можете видеть, что SpringBoot основан наSpringApplicationRunListenerЭтот интерфейс SPI идет кspring.factoriesЗагрузите соответствующий класс реализации расширения SPI, мы переходим непосредственно кspring.factoriesпосмотриSpringApplicationRunListenerКакие классы реализации SPI:

Как видно из приведенного выше рисунка,SpringApplicationRunListenerТолькоEventPublishingRunListenerЭтот класс реализации SPIEventPublishingRunListenerЭтот партнер особенно важен в процессе запуска SpringBoot, который генерирует различные события жизненного цикла SpringBoot на разных этапах процесса запуска SpringBoot.которыйSpringApplicationRunListenersОбъекты не отвечают за трансляцию событий, но в конечном итоге делегируютсяEventPublishingRunListenerЭтот чувак пришел вести трансляцию.

потому что изspring.factoriesзагрузкаEventPublishingRunListenerКласс будет создан после класса, затем мы продолжимEventPublishingRunListenerисходный код, чтобы увидеть, как он берет на себя ответственность за создание событий жизненного цикла SpringBoot?

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

можно увидетьEventPublishingRunListenerкласс реализуетSpringApplicationRunListenerинтерфейс,SpringApplicationRunListenerИнтерфейс определяет методы интерфейса для генерации событий жизненного цикла при запуске SpringBoot иEventPublishingRunListenerкласс реализованSpringApplicationRunListenerинтерфейсstarting,environmentPreparedиcontextPreparedи другие методы для трансляции различных событий жизненного цикла SpringBoot, давайте посмотрим непосредственноSpringApplicationRunListenerИсходный код интерфейса готов:

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

Давайте проанализируемEventPublishingRunListenerЭтот класс, вы можете видеть, что он имеет важный атрибут членаinitialMulticaster, свойство членаSimpleApplicationEventMulticasterОбъект класса, отвечающий за трансляцию событий жизненного цикла при запуске SpringBoot,которыйEventPublishingRunListenerОбъекты не отвечают за трансляцию событий, но в конечном итоге делегируютсяSimpleApplicationEventMulticasterЭтот чувак пришел вести трансляцию.отEventPublishingRunListenerтакже можно увидеть в исходном кодеstarting,environmentPreparedиcontextPreparedи так далее, именно по вызовуSimpleApplicationEventMulticasterобъект классаmulticastEventметод трансляции события.

считатьКогда событие генерируется во время процесса запуска SpringBoot, отправитель события делегируется слой за слоем.SpringApplicationRunListenersпредполагает объект, тоSpringApplicationRunListenersОбъект делегирует ответственность за трансляцию событийEventPublishingRunListenerобъект, в конце концовEventPublishingRunListenerОбъект делегирует ответственность за трансляцию событийSimpleApplicationEventMulticasterобъект.Почему вы хотите делегировать это слой за слоем?Об этом стоит подумать.

упоминалось ранее изspring.factoriesвыгрузитьEventPublishingRunListenerКласс будет создан позже, и создание экземпляра обязательно пройдетEventPublishingRunListenerКонструктор для создания экземпляра, поэтому давайте проанализируем его далееEventPublishingRunListenerИсходный код конструктора:

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

можно увидеть вEventPublishingRunListenerв конструкторе естьforЦикл будет проходить отspring.factoriesСлушатели, загруженные в набор, затем добавляются в набор и кешируются, и их можно напрямую брать из этого набора при трансляции различных событий в будущем, вместо того, чтобы идти вspring.factoriesсредняя загрузка для повышения эффективности.

3.2 Трансляция встроенных событий жизненного цикла SpringBoot

отspring.factoriesЗагружается и создается в файле конфигурацииEventPublishingRunListenerПосле объекта во время процесса запуска SpringBoot будет сгенерирована серия встроенных событий жизненного цикла SpringBoot.Давайте рассмотрим исходный код во время процесса запуска 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 генерируется в общей сложности 7 различных типов событий жизненного цикла, чтобы отметить различные этапы запуска SpringBoot, В то же время слушатели этих событий жизненного цикла также будут выполнять некоторую логику инициализации во время Процесс запуска, логика инициализации этих слушателей будет проанализирована в следующей статье. Ниже приведены типы событий, которые будут генерироваться во время запуска SpringBoot, гдеApplicationFailedEventОн генерируется только тогда, когда во время процесса запуска SpringBoot возникает исключение:

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

мы начинаем сlisteners.starting();Возьмите этот код в качестве примера, см.EventPublishingRunListenerИсходный код события эмиссии объекта:

// SpringApplicationRunListeners.java

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

следовать заlistener.starting();исходный код:

EventPublishingRunListener.java

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

можно увидеть,EventPublishingRunListenerобъект будет опубликованApplicationStartingEventэто дело возложено наSimpleApplicationEventMulticasterобъектinitialMulticaster, ,иinitialMulticasterобъект в конечном итоге вызовет свойmulticastEventметод испусканияApplicationStartingEventсобытие. оSimpleApplicationEventMulticasterКак классы транслируют события, у автора естьКак Spring реализует механизм мониторинга событий? Исходный код Spring (2)Эта статья была подробно проанализирована и не будет здесь повторяться.

Исходный код других событий жизненного цикла, возникающих при запуске SpringBoot, здесь анализироваться не будет.

4 Сводка встроенных событий жизненного цикла SpringBoot

Что ж, различные события жизненного цикла, которые будут генерироваться во время процесса запуска SpringBoot, были проанализированы.Следующая таблица резюмирует:

5 Резюме

На этом анализ исходного кода широковещательных событий жизненного цикла во время запуска SpringBoot завершается.В следующей статье мы продолжим знакомство со слушателями, которые прослушивают эти события жизненного цикла. Давайте рассмотрим содержание этой статьи и резюмируем ключевые моменты:

Во время процесса запуска SpringBoot будут генерироваться 7 типов событий жизненного цикла, отмечая различные фазы запуска, а затем соответствующие прослушиватели будут прослушивать эти события, чтобы выполнить некоторую логическую работу по инициализации.

[Примечания к источнику] Проект анализа исходного кода Github доступен онлайн! ! ! Ниже приведен адрес Github заметки:

GitHub.com/Примечания к источнику/…

Категории