Adresse Github du projet d'annotation chinois SpringBoot:
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 .
SpringApplication
Le processus de construction de l'objet consiste en fait à affecter des valeurs aux 6 variables membres de laSpringApplication
classe ;- 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.factories
fichier 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.properties
les 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 SpringApplicationRunListeners
objet est utilisé pour SpringBoot de transmission lors du démarrage de divers événements de cycle de vie, comme le lancement ApplicationStartingEvent
, ApplicationEnvironmentPreparedEvent
et ApplicationContextInitializedEvent
ainsi 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 SpringApplication
processus 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 SpringApplication
fonction de l' ApplicationListener
interface 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 SpringApplication
lors de la construction d' objets setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
.
Ce code est do de la spring.factories
charge dans l' ApplicationListener
écouteur d'événement interface SPI étendue classe d'implémentation, puis ajouter à SpringApplication
l'objet listeners
dans 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 ApplicationListener
interfaces, qui sont spring.factories
partiellement 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 SpringApplicationRunListeners
objet 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. getSpringFactoriesInstances
Nous 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 SpringApplicationRunListener
cette interface SPI spring.factories
. Allons directement pour spring.factories
voir SpringApplicationRunListener
quelles classes d'implémentation SPI sont là:
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, SpringApplicationRunListeners
l'objet ne suppose pas des événements de diffusion de la responsabilité, Finalement, EventPublishingRunListener
le copain a été chargé de diffuser l'événement.
En raison de spring.factories
la charge EventPublishingRunListener
lorsque la classe instanciera la classe, puis nous suivons EventPublishingRunListener
le 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 EventPublishingRunListener
outils de classe de SpringApplicationRunListener
l'interface, SpringApplicationRunListener
l'interface définit la méthode d'interface de transmission d' événements de cycle de vie quand SpringBoot commencer, alors que la EventPublishingRunListener
classe pour y parvenir est par le biais de SpringApplicationRunListener
l'interface starting
, environmentPrepared
et les contextPrepared
événements de cycle de vie de SpringBoot de diffusion différents et ainsi de suite, nous regardons la directe SpringApplicationRunListener
interface 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 EventPublishingRunListener
cette classe, nous pouvons voir qu'elle a un attribut membre important initialMulticaster
, l'attribut membre est un SimpleApplicationEventMulticaster
objet 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' EventPublishingRunListener
objet n'assume pas la responsabilité de la diffusion des événements, Finalement, SimpleApplicationEventMulticaster
le copain a été chargé de diffuser l'événement. EventPublishingRunListener
On peut également voir à partir du code source que starting
, dans des méthodes telles que He environmentPrepared
et ainsi de contextPrepared
suite, c'est aussi en appelant des méthodes d' SimpleApplicationEventMulticaster
objets de classe multicastEvent
pour 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
SpringApplicationRunListeners
assumé par l' objet, puis l'SpringApplicationRunListeners
objet délègue la responsabilité de la diffusion des événements à l'EventPublishingRunListener
objet, et enfin l'EventPublishingRunListener
objet délègue la responsabilité de la diffusion des événements à l'SimpleApplicationEventMulticaster
objet. Pourquoi déléguez-vous cela à des calques? Cela mérite réflexion.
De ce qui précède mentionnés spring.factories
chargement hors EventPublishingRunListener
lorsque la classe est instancié, le instancié lié par EventPublishingRunListener
le constructeur à instancier, nous avons analysé ensuite la EventPublishingRunListener
source 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 EventPublishingRunListener
le constructeur il y a une for
itère en boucle jusqu'à ce que la spring.factories
charge 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.factories
au chargement, améliorez l'efficacité.
3.2 Diffuser les événements du cycle de vie intégrés de SpringBoot
Après avoir spring.factories
chargé et instancié l' EventPublishingRunListener
objet à 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 ApplicationFailedEvent
cours du processus de démarrage SpringBoot, dans lesquels une exception sera émise au cours du processus de démarrage SpringBoot:
ApplicationStartingEvent
ApplicationEnvironmentPreparedEvent
ApplicationContextInitializedEvent
ApplicationPreparedEvent
ApplicationStartedEvent
ApplicationFailedEvent
ApplicationReadyEvent
Prenons listeners.starting();
ce code comme exemple et regardons EventPublishingRunListener
le 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' EventPublishingRunListener
objet ApplicationStartingEvent
délègue ce sujet à l' SimpleApplicationEventMulticaster
objet initialMulticaster
, et l' initialMulticaster
objet appellera éventuellement ses multicastEvent
méthodes pour émettre des ApplicationStartingEvent
événements. Concernant la SimpleApplicationEventMulticaster
faç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:
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.