Dirección de Github del proyecto de anotación china SpringBoot:
¿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 .
SpringApplication
El proceso de construcción del objeto es en realidad asignar valores aSpringApplication
las 6 variables miembro de la clase ;- 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.factories
archivo 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 ConfigFileApplicationListener
escuchar onApplicationEnvironmentPreparedEvent
eventos para cargar application.properties
variables 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 SpringApplicationRunListeners
objeto se utiliza para SpringBoot de transmisión durante el inicio de varios eventos del ciclo de vida, tales como lanzamiento ApplicationStartingEvent
, ApplicationEnvironmentPreparedEvent
y ApplicationContextInitializedEvent
así 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 SpringApplication
proceso 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 SpringApplication
acuerdo con la ApplicationListener
interfaz 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 SpringApplication
al construir objetos setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
.
Este código es hacer de la spring.factories
carga en el ApplicationListener
detector de eventos interfaz SPI extendió clase de implementación y luego añadir SpringApplication
al objeto listeners
en 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 ApplicationListener
interfaces, que se spring.factories
configuran 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 SpringApplicationRunListeners
objeto 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. getSpringFactoriesInstances
Ya 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 SpringApplicationRunListener
esta interfaz SPI spring.factories
. Vayamos directamente a spring.factories
ver SpringApplicationRunListener
qué clases de implementación SPI hay:
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, SpringApplicationRunListeners
el objeto no asume eventos responsabilidad de difusión, Al final, EventPublishingRunListener
el amigo fue el encargado de transmitir el evento.
Porque a partir de spring.factories
la carga EventPublishingRunListener
cuando la clase será una instancia de la clase, y luego seguimos hasta EventPublishingRunListener
el 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 EventPublishingRunListener
instrumentos de la clase SpringApplicationRunListener
de la interfaz, SpringApplicationRunListener
la interfaz define el método de interfaz de transmisión de eventos del ciclo de vida cuando SpringBoot empezar, mientras que la EventPublishingRunListener
clase de lograrlo es a través de SpringApplicationRunListener
la interfaz starting
, environmentPrepared
y contextPrepared
eventos del ciclo de vida de difusión SpringBoot y así sucesivamente, nos fijamos en la directa SpringApplicationRunListener
interfaz 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 EventPublishingRunListener
esta clase, podemos ver que tiene un atributo miembro importante initialMulticaster
, el atributo miembro es un SimpleApplicationEventMulticaster
objeto de clase, esta clase es responsable de transmitir los eventos del ciclo de vida del inicio de SpringBoot, es decirEventPublishingRunListener
SimpleApplicationEventMulticaster
, el objeto no asume la responsabilidad de transmitir eventos Al final, el amigo fue el encargado de transmitir el evento. EventPublishingRunListener
También se puede ver en el código fuente que starting
, en métodos como He, environmentPrepared
etc. contextPrepared
, también se llama a métodos de SimpleApplicationEventMulticaster
objetos de clase multicastEvent
para 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
SpringApplicationRunListeners
asume el objeto, y luego elSpringApplicationRunListeners
objeto delega la responsabilidad de transmitir eventos alEventPublishingRunListener
objeto, y finalmente elEventPublishingRunListener
objeto delega la responsabilidad de transmitir eventos alSimpleApplicationEventMulticaster
objeto. ¿Por qué delegas esto a las capas? Vale la pena pensar en esto.
De lo anterior mencionados spring.factories
cargar a cabo EventPublishingRunListener
cuando se crea una instancia de la clase, la instancia obligado por EventPublishingRunListener
el constructor para ser instanciado, analizamos siguiente la EventPublishingRunListener
fuente 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 EventPublishingRunListener
el constructor hay un for
itera bucle hasta que la spring.factories
carga 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.factories
a cargar, mejore la eficiencia.
3.2 Transmitir eventos de ciclo de vida integrados de SpringBoot
Después de spring.factories
cargar e instanciar el EventPublishingRunListener
objeto 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 ApplicationFailedEvent
durante el proceso de inicio de SpringBoot, en el que se emitirá una excepción durante el proceso de inicio de SpringBoot:
ApplicationStartingEvent
ApplicationEnvironmentPreparedEvent
ApplicationContextInitializedEvent
ApplicationPreparedEvent
ApplicationStartedEvent
ApplicationFailedEvent
ApplicationReadyEvent
Tomemos listeners.starting();
este código como ejemplo y observemos EventPublishingRunListener
el 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 EventPublishingRunListener
objeto ApplicationStartingEvent
delega este asunto al SimpleApplicationEventMulticaster
objeto initialMulticaster
, y el initialMulticaster
objeto eventualmente llamará a sus multicastEvent
métodos para emitir ApplicationStartingEvent
eventos. Con respecto a SimpleApplicationEventMulticaster
có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:
¡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.