Análisis del código fuente del mecanismo de supervisión de eventos SpringBoot (activado) Código fuente SpringBoot (nueve)

Dirección de Github del proyecto de anotación china SpringBoot:

github.com/yuanmabiji/…

¿Cómo se construye el objeto SpringApplication en este artículo ? Código fuente de SpringBoot (ocho)

1 Aprende del pasado

Sabiendo algo nuevo, revisemos brevemente el contenido del artículo anterior. En el último artículo, analizamos el proceso de construcción del objeto SpringApplication y un conjunto de mecanismos SPI implementados por SpringBoot .

  1. SpringApplicationEl proceso de construcción del objeto es en realidad asignar valores a SpringApplicationlas 6 variables miembro de la clase ;
  2. SpringBoot implementa su propio mecanismo SPI a través de los siguientes pasos:
  • 1) Primero obtenga el cargador de clase de contexto de hilo;
  • 2) Luego use el cargador de clases de contexto para cargar todas las clases de implementación de extensión SPI desde el spring.factoriesarchivo de configuración y ponerlas en el caché ;
  • 3) De acuerdo con la interfaz SPI, elimine la clase de implementación de extensión SPI correspondiente del caché;
  • 4) Instanciar y devolver la clase de implementación de extensión SPI tomada del caché.

2 Introducción

Durante el proceso de inicio de SpringBoot, cada etapa de inicio diferente transmitirá diferentes eventos de ciclo de vida integrados, y luego el oyente correspondiente escuchará estos eventos para realizar un trabajo de lógica de inicialización, como ConfigFileApplicationListenerescuchar onApplicationEnvironmentPreparedEventeventos para cargar application.propertiesvariables de entorno del archivo de configuración .

Por lo tanto, este artículo analizará el código fuente del mecanismo de monitoreo de eventos de SpringBoot en el futuro.

3 SpringBoot difunde análisis de proceso de eventos de ciclo de vida incorporado

Para explorar el proceso de evento de ciclo de vida incorporado de transmisión de SpringBoot, revisemos el código del proceso de inicio de 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 primero será visto por primera vez en el proceso de inicio de un nuevo SpringApplicationRunListenersobjeto se utiliza para SpringBoot de transmisión durante el inicio de varios eventos del ciclo de vida, tales como lanzamiento ApplicationStartingEvent, ApplicationEnvironmentPreparedEventy ApplicationContextInitializedEventasí sucesivamente, entonces el oyente correspondiente realizar la inicialización lógica durante el inicio de algunas de SpringBoot . Entonces, ¿cuándo se cargan e instancian los oyentes que escuchan estos eventos del ciclo de vida de SpringBoot? ¿Recuerdas el SpringApplicationproceso de análisis del último artículo ? Así es, estos oyentes que realizan la lógica de inicialización se cargan y se instancian en el archivo de configuración de SpringApplicationacuerdo con la ApplicationListenerinterfaz durante el proceso de construcción spring.factories.

3.1 Preparación para la transmisión de los eventos de ciclo de vida integrados de SpringBoot

3.1.1 Cargar clase de implementación de escucha de ApplicationListener

¿Repasemos cómo se construye el objeto SpringApplication? El artículo del código fuente de SpringBoot (ocho) habla sobre este código SpringApplicational construir objetos setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));.

Este código es hacer de la spring.factoriescarga en el ApplicationListenerdetector de eventos interfaz SPI extendió clase de implementación y luego añadir SpringApplicational objeto listenersen la colección de eventos de inicio SpringBoot posterior de escucha, la lógica de inicialización para realizar algún trabajo.

Los oyentes específicos en el momento del inicio de SpringBoot han implementado ApplicationListenerinterfaces, que se spring.factoriesconfiguran parcialmente de la siguiente manera:

Sin embargo, durante la depuración, los oyentes se cargan desde todos los archivos de configuración de spring.factories, y finalmente se cargan 10 oyentes. Como se muestra a continuación:

3.1.2 Cargar clase de extensión SPI EventPublishingRunListener

Como se mencionó anteriormente, en el proceso de inicio de SpringBoot, primero se creará un nuevo SpringApplicationRunListenersobjeto para lanzar los eventos del ciclo de vida en el proceso de inicio de SpringBoot. Es decir, veamos SpringApplicationRunListeners listeners = getRunListeners(args);este código:

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

复制代码

Nos centraremos en getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)esta frase de código. getSpringFactoriesInstancesYa estamos familiarizados con este método. Hemos analizado este método en detalle en el artículo anterior al analizar el mecanismo SPI de Spring Boot. Se puede ver que SpringBoot ahora está cargando la clase de implementación de extensión SPI correspondiente de acuerdo con SpringApplicationRunListeneresta interfaz SPI spring.factories. Vayamos directamente a spring.factoriesver SpringApplicationRunListenerqué clases de implementación SPI hay:

Se puede ver en el gráfico, SpringApplicationRunListener solamente EventPublishingRunListener la clase de implementación de SPI EventPublishingRunListener este tipo es especialmente importante durante SpringBoot inicio, los eventos del ciclo de vida de emisión diferente SpringBoot por sus diferentes etapas del proceso de inicio en SpringBoot, es decir, SpringApplicationRunListenersel objeto no asume eventos responsabilidad de difusión, Al final, EventPublishingRunListenerel amigo fue el encargado de transmitir el evento.

Porque a partir de spring.factoriesla carga EventPublishingRunListenercuando la clase será una instancia de la clase, y luego seguimos hasta EventPublishingRunListenerel código fuente para ver cómo se va a llevar a cabo los eventos del ciclo de vida SpringBoot emisión de esa responsabilidad?

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

复制代码

Se puede ver los EventPublishingRunListenerinstrumentos de la clase SpringApplicationRunListenerde la interfaz, SpringApplicationRunListenerla interfaz define el método de interfaz de transmisión de eventos del ciclo de vida cuando SpringBoot empezar, mientras que la EventPublishingRunListenerclase de lograrlo es a través de SpringApplicationRunListenerla interfaz starting, environmentPreparedy contextPreparedeventos del ciclo de vida de difusión SpringBoot y así sucesivamente, nos fijamos en la directa SpringApplicationRunListenerinterfaz a la fuente de buena 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);
}
复制代码

Luego analizamos EventPublishingRunListeneresta clase, podemos ver que tiene un atributo miembro importante initialMulticaster, el atributo miembro es un SimpleApplicationEventMulticasterobjeto de clase, esta clase es responsable de transmitir los eventos del ciclo de vida del inicio de SpringBoot, es decirEventPublishingRunListenerSimpleApplicationEventMulticaster , el objeto no asume la responsabilidad de transmitir eventos Al final, el amigo fue el encargado de transmitir el evento. EventPublishingRunListenerTambién se puede ver en el código fuente que starting, en métodos como He, environmentPreparedetc. contextPrepared, también se llama a métodos de SimpleApplicationEventMulticasterobjetos de clase multicastEventpara transmitir eventos.

Tenga en cuenta que cuando el evento se inicia durante el inicio de SpringBoot, el emisor del evento delega responsabilidades capa por capa, lo que inicialmente SpringApplicationRunListenersasume el objeto, y luego el SpringApplicationRunListenersobjeto delega la responsabilidad de transmitir eventos al EventPublishingRunListenerobjeto, y finalmente el EventPublishingRunListenerobjeto delega la responsabilidad de transmitir eventos al SimpleApplicationEventMulticasterobjeto. ¿Por qué delegas esto a las capas? Vale la pena pensar en esto.

De lo anterior mencionados spring.factoriescargar a cabo EventPublishingRunListenercuando se crea una instancia de la clase, la instancia obligado por EventPublishingRunListenerel constructor para ser instanciado, analizamos siguiente la EventPublishingRunListenerfuente constructor:

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

Se puede observar en EventPublishingRunListenerel constructor hay un foritera bucle hasta que la spring.factoriescarga de los oyentes A continuación se añadieron a la colección almacenada en caché para después tomadas directamente de este conjunto a cuando varios eventos transmitidos en vez Luego vaya spring.factoriesa cargar, mejore la eficiencia.

3.2 Transmitir eventos de ciclo de vida integrados de SpringBoot

Después de spring.factoriescargar e instanciar el EventPublishingRunListenerobjeto del archivo de configuración, se lanzará una serie de eventos de ciclo de vida integrados de SpringBoot durante el proceso de inicio de SpringBoot. Revisemos el código fuente durante el proceso de inicio de 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;
}
复制代码

Se puede ver que durante el proceso de arranque de Spring Boot, se emitirán un total de 7 tipos diferentes de eventos de ciclo de vida para marcar las diferentes fases de arranque de Spring Boot. Al mismo tiempo, los oyentes de estos eventos de ciclo de vida también realizarán cierta lógica de inicialización durante el proceso de arranque. La lógica de inicialización de estos oyentes se analizará en el próximo artículo. Los siguientes son los tipos de eventos que se emitirán ApplicationFailedEventdurante el proceso de inicio de SpringBoot, en el que se emitirá una excepción durante el proceso de inicio de SpringBoot:

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

Tomemos listeners.starting();este código como ejemplo y observemos EventPublishingRunListenerel código fuente del evento de emisión del objeto:

// SpringApplicationRunListeners.java

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

Continúe siguiendo listener.starting();el código fuente:

EventPublishingRunListener.java

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

Como puede ver, el EventPublishingRunListenerobjeto ApplicationStartingEventdelega este asunto al SimpleApplicationEventMulticasterobjeto initialMulticaster, y el initialMulticasterobjeto eventualmente llamará a sus multicastEventmétodos para emitir ApplicationStartingEventeventos. Con respecto a SimpleApplicationEventMulticastercómo la clase transmite eventos, ¿cómo ha implementado el autor el mecanismo de monitoreo de eventos en Spring? Este artículo del código fuente de Spring (2) ha sido analizado en detalle y no se repetirá aquí.

El código fuente para lanzar otros eventos del ciclo de vida durante el proceso de inicio de SpringBoot no se analiza aquí

4 Resumen de los eventos de ciclo de vida integrados de SpringBoot

Bueno, he analizado varios eventos del ciclo de vida que se lanzarán durante el proceso de inicio de SpringBoot. La siguiente tabla resume:

5 Resumen

Este es el final del análisis del código fuente de los eventos del ciclo de vida de la transmisión durante el proceso de inicio de SpringBoot. Revisamos los puntos clave en este artículo:

SpringBoot lanzará 7 tipos de eventos de ciclo de vida durante el proceso de inicio, marcando diferentes etapas de inicio, y luego los oyentes correspondientes escucharán estos eventos para realizar un trabajo de lógica de inicialización.

[Notas fuente] ¡El proyecto de análisis de código fuente de Github está en línea! ! ! La siguiente es la dirección de Github de la nota:

github.com/yuanmabiji/…

¡Los me gusta y los reenvíos son la mayor motivación para el autor!


Número público [ notas fuente ], centrándose en el análisis del código fuente del marco de la serie back-end de Java.

Supongo que te gusta

Origin juejin.im/post/5e92cde8f265da47e22f1fdb
Recomendado
Clasificación