Адрес Github китайского аннотационного проекта SpringBoot:
GitHub.com/Примечания к источнику/…
Эта статья продолжаетКак устроен объект SpringApplication? Исходный код SpringBoot (8)
1 Уроки прошлого
Ознакомившись со старым и узнав новое, давайте вкратце повторим содержание предыдущей статьи.В предыдущей статье мы разобралиПроцесс построения объекта SpringApplication и набор механизмов SPI, реализованных самим SpringBoot, ключевые шаги теперь сжаты и обобщены:
-
SpringApplication
Процесс строительства объекта фактически заключается в том, чтобы датьSpringApplication
Категория6присвоение переменных-членов; - 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 возникает исключение:
ApplicationStartingEvent
ApplicationEnvironmentPreparedEvent
ApplicationContextInitializedEvent
ApplicationPreparedEvent
ApplicationStartedEvent
ApplicationFailedEvent
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 заметки: