Серия SpringBoot — механизм событий

Spring Boot Spring

Публичный аккаунт WeChat:студия gmapper
Колонка самородков:glmapper
Вейбо:Сумасшедший Stone_henu
Добро пожаловать, чтобы обратить внимание, учиться и делиться технологиями вместе

в этой статьеПоговорим о механизме расширения в Spring (1)средняя параSpringАнализируется механизм события. тогда дляSpringBootНапример, это вSpringКакие расширения были сделаны на его основе? Поговорим об этом в будущемSpringBootсобытия в .

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

  • SpringApplicationRunListener
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
  • ApplicationListener
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

SpringApplicationRunListenerклассSpringBootновый класс в .SpringApplicationиспользуйте их в классе для косвенного вызоваApplicationListener. Еще один новый классSpringApplicationRunListeners,SpringApplicationRunListenersсодержит несколькоSpringApplicationRunListener.

SpringApplicationRunListener

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

Давайте взглянемSpringApplicationRunListenerКод интерфейса:

public interface SpringApplicationRunListener {
	//当run方法首次启动时立即调用。可用于非常早期的初始化。
	void starting();
	//在准备好环境后,但在创建ApplicationContext之前调用。
	void environmentPrepared(ConfigurableEnvironment environment);
	//在创建和准备好ApplicationContext之后,但在加载源之前调用。
	void contextPrepared(ConfigurableApplicationContext context);
	//在加载应用程序上下文后但刷新之前调用
	void contextLoaded(ConfigurableApplicationContext context);
	//上下文已刷新,应用程序已启动,但尚未调用commandlinerunner和applicationrunner。
	void started(ConfigurableApplicationContext context);
	//在运行方法完成之前立即调用,此时应用程序上下文已刷新,
	//并且所有commandlinerunner和applicationrunner都已调用。
	//2.0 才有
	void running(ConfigurableApplicationContext context);
	//在运行应用程序时发生故障时调用。2.0 才有
	void failed(ConfigurableApplicationContext context, Throwable exception);
}

SpringApplicationRunListeners

упомянутый выше,SpringApplicationRunListenersдаSpringApplicationRunListenerколлекция, включающая множествоSpringApplicationRunListenerпример;SpringApplicationКласс фактически используетSpringApplicationRunListenersкласс, сSpringApplicationRunListenerЖизненный цикл тот же, называяSpringApplicationRunListener. Затем транслируйте соответствующее событие наApplicationListener.

Подробности смотрите в коде:SpringApplicationRunListeners.

EventPublishingRunListener

EventPublishingRunListenerклассSpringApplicationRunListenerКласс реализации интерфейса, который имеет функцию трансляции событий. его внутреннее использованиеApplicationEventMulticasterСобытие публикуется до фактического обновления контекста. Посмотрите нижеEventPublishingRunListenerСобытия, соответствующие жизненному циклу класса.

ApplicationStartingEvent

ApplicationStartingEventдаSpringBootСобытие, которое выполняется при запуске автозагрузки, что можно получить в этом событииSpringApplicationобъект, вы можете сделать некоторые настройки перед выполнением, соответствующий метод вызоваstarting().

ApplicationEnvironmentPreparedEvent

ApplicationEnvironmentPreparedEventдаSpringBootсоответствоватьEnviromentСобытие, которое выполняется, когда оно готово, контекст в это времяcontextЕще не создан. получено в этом монитореConfigurableEnvironmentПосле этого вы можете выполнять операции с информацией о конфигурации, такие как изменение информации о конфигурации по умолчанию, добавление дополнительной информации о конфигурации и т. д. Соответствующий метод жизненного циклаenvironmentPrepared(environment);SpringCloud, в этот момент инициализируется контекст загрузки.

ApplicationContextInitializedEvent

когдаSpringApplicationи готовApplicationContext, а при загрузке любогоbeanвызывается перед определениемApplicationContextInitializersопубликованы события. Соответствующий метод жизненного циклаcontextPrepared()

ApplicationPreparedEvent

ApplicationPreparedEventдаSpringBootконтекстcontextСоздание завершено — это публикуемое событие, но на этот разspringсерединаbeanЕще не полностью загружен. Здесь контекст может быть передан для выполнения некоторых дополнительных операций. Но в этом слушателе нет возможности получить кастомныйbeanи работать. Соответствующий метод жизненного циклаcontextLoaded().

ApplicationStartedEvent

Это событие было введено в версии 2.0; конкретный выпуск заключается в том, что после обновления контекста приложения любой вызовApplicationRunnerиCommandLineRunnerперед запуском программы.

ApplicationReadyEvent

это иApplicationStartedEventОчень похоже, он также вызывается после обновления контекста приложения, разница в том, что в это времяApplicationRunnerиCommandLineRunnerзавершил вызов, что также означает, чтоSpringBootЗагрузка завершена.

ApplicationFailedEvent

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

демо и порядок выполнения каждого события

Распечатаны демо, соответствующие следующим событиям, и порядок выполнения.

  • GlmapperApplicationStartingEventListener
public class GlmapperApplicationStartingEventListener implements ApplicationListener<ApplicationStartingEvent> {
    @Override
    public void onApplicationEvent(ApplicationStartingEvent applicationStartingEvent) {
        System.out.println("execute ApplicationStartingEvent ...");
    }
}
  • GlmapperApplicationEnvironmentPreparedEvent
public class GlmapperApplicationEnvironmentPreparedEvent implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent applicationEnvironmentPreparedEvent) {
        System.out.println("execute ApplicationEnvironmentPreparedEvent ...");
    }
}
  • GlmapperApplicationContextInitializedEvent
public class GlmapperApplicationContextInitializedEvent implements ApplicationListener<ApplicationContextInitializedEvent> {
    @Override
    public void onApplicationEvent(ApplicationContextInitializedEvent applicationContextInitializedEvent) {
        System.out.println("execute applicationContextInitializedEvent ...");
    }
}
  • GlmapperApplicationPreparedEvent
public class GlmapperApplicationPreparedEvent implements ApplicationListener<ApplicationPreparedEvent> {
    @Override
    public void onApplicationEvent(ApplicationPreparedEvent applicationPreparedEvent) {
        System.out.println("execute ApplicationPreparedEvent ...");
    }
}
  • GlmapperApplicationStartedEvent
public class GlmapperApplicationStartedEvent implements ApplicationListener<ApplicationStartedEvent> {
    @Override
    public void onApplicationEvent(ApplicationStartedEvent applicationStartedEvent) {
        System.out.println("execute ApplicationStartedEvent ...");
    }
}
  • GlmapperApplicationReadyEvent
public class GlmapperApplicationReadyEvent implements ApplicationListener<ApplicationReadyEvent> {
    @Override
    public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
        System.out.println("execute ApplicationReadyEvent ...");
    }
}
  • Результаты

Архитектура событий в SpringBoot

здесьSpringApplicationRunListenerДля этого класса. в классе реализацииEventPublishingRunListener, существует два режима публикации событий:

  • пройти черезSimpleApplicationEventMulticasterтранслировать событие
  • Все слушатели передаются в соответствующиеContext

такEventPublishingRunListenerНе только ответственность за публикацию событий, но и в нужное времяSpringApplicationПолученный слушатель связан с контекстом приложения.

SimpleApplicationEventMulticaster

SimpleApplicationEventMulticasterдаSpringТранслятор событий по умолчанию. Давайте посмотрим, как это работает:

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        Executor executor = getTaskExecutor();
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            invokeListener(listener, event);
        }
    }
}

Как вы можете видеть из приведенного выше фрагмента кода, он вызывает каждого слушателя, проходя через каждый зарегистрированный слушатель и запускаяonApplicationEventметод.

Давайте посмотрим нижеSimpleApplicationEventMulticasterСтруктура интеграции класса:

здесьAbstractApplicationContextДавайте поговорим об этом, этот класс фактически отвечает за инициализацию системы событий.

Инициализация системы событий

Инициализация системы событий соответствуетSpringBootпроцесс запускаrefreshContextСюда;refreshContextВ частности, вызовите метод AbstractApplicationContext.refresh() и, наконец, вызовите initApplicationEventMulticaster(), чтобы завершить инициализацию системы событий. Код выглядит следующим образом:

Пользователи могут определить собственный вещатель событий для контейнера, если реализацияApplicationEventMulticasterВот и все,SpringОн будет зарегистрирован как распространитель событий контейнера через механизм отражения.Если настроенный внешний распространитель событий не найден,Springиспользуется по умолчаниюSimpleApplicationEventMulticasterкак ведущий событий.

регистрация на мероприятие

Регистрация событий выполняется после завершения инициализации системы событий, а такжеAbstractApplicationContext.refresh()вызывается метод.

Здесь делаются три вещи:

  • Сначала зарегистрируйте статически указанныйlisteners; сюда входят те прослушиватели, которые мы настроили.
  • перечислитьDefaultListableBeanFactoryсерединаgetBeanNamesForTypeполучить обычайApplicationListener beanЗарегистрируйтесь на мероприятия.
  • Трансляция ранних событий.

трансляция события

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

org.springframework.context.support.AbstractApplicationContext#publishEvent

Событие в EarlyApplicationEvents предназначено для сохранения информации об уведомлении, когда вещатель не установлен.Как только контейнер будет установлен, он будет уведомлен непосредственно в будущем.

Широковещательное событие в конечном итоге вызываетсяApplicationEventMulticasterизmulticastEventреализовать. иmulticastEventТо есть способ исполнения события.

выполнение события

вышеSimpleApplicationEventMulticasterРаздел уже представленmulticastEventСюда. добавь если естьtaskExecutorбудет использовать параллельный режим для выполнения событий, но на самом делеSimpleApplicationEventMulticasterРеализации пула потоков не предусмотрено.По умолчанию события выполняются синхронно (org.springframework.core.task.SyncTaskExecutor), поэтому, если вам нужна асинхронная конфигурация, вам нужно реализовать пул потоков самостоятельно.

Фаза события в процессе запуска SpringBoot

вернуться сюдаSpringApplicationизrunметод см.SpringBootЧто делает каждая фаза события во время запуска.

starting -> ApplicationStartingEvent

здесьdebugприбытьstartingметод, восходящий кmulticastEvent,здесьtypeзаApplicationStartingEvent; соответствующие события таковы:

  • LoggerApplicationListener: настроить систему ведения журнала. использоватьlogging.configКонфигурация, указанная переменной среды, или конфигурация по умолчанию
  • BackgroundPreinitializer: запуск некоторых трудоемких задач инициализации как можно раньше с использованием фонового потока.
  • DelegatingApplicationListener: перенаправить в переменные среды после прослушивания событийcontext.listener.classesуказанные прослушиватели событий
  • LiquibaseServiceLocatorApplicationListener: используйтеSpringBootисполняемыйjarПакеты работают с заменой версийliquibase ServiceLocator

listeners.environmentPrepared->ApplicationEnvironmentPreparedEvent

  • AnsiOutputApplicationListener: согласноspring.output.ansi.enabledконфигурация параметровAnsiOutput

  • ConfigFileApplicationListener:EnvironmentPostProcessor, читать файлы конфигурации из общепринятых мест, например из следующих каталоговapplication.properties,application.ymlи другие файлы конфигурации:

    • classpath:
    • file:.
    • classpath:config
    • file:./config/

    Его также можно настроить для чтения файлов конфигурации из других указанных мест.

  • ClasspathLoggingApplicationListener: событие готово для средыApplicationEnvironmentPreparedEvent/применить не удается件ApplicationFailedEventответить на журналDEBUGвыходной уровеньTCCL(thread context class loader)изclasspath.

  • FileEncodingApplicationListener: прекращает запуск приложения, если кодировка системного файла отличается от указанной в переменной среды. Конкретный метод заключается в сравнении свойств системыfile.encodingи переменные окруженияspring.mandatory-file-encodingОни равны (без учета регистра).

listeners.contextPrepared->ApplicationContextInitializedEvent

Связанные слушатели относятся к описанию выше.

listeners.contextLoaded->ApplicationPreparedEvent

Связанные слушатели относятся к описанию выше.

refresh->ContextRefreshedEvent

  • ConditionEvaluationReportLoggingListener: на самом деле реализованоApplicationContextInitializerинтерфейс, целью которого являетсяConditionEvaluationReportДля записи в журнал используйтеDEBUGвыход уровня. Отчет о сбое программы вызывает вывод сообщения, в котором пользователю предлагается отобразить отчет в режиме отладки. Это связано сConditionEvaluationReportListenerпрослушиватель событий, а затем вывод, когда происходит соответствующее событиеConditionEvaluationReportОтчет.
  • ClearCachesApplicationListener: после загрузки контекста приложения очистить кеш и реагировать на события.ContextRefreshedEvent.
  • SharedMetadataReaderFactoryContextInitializer: КомуcontextзарегистрировалBeanFactoryPostProcessor:CachingMetadataReaderFactoryPostProcessorпример.
  • Ресурсурлпровидер:handling mappingsиметь дело с

started->ApplicationStartedEvent

Связанные слушатели относятся к описанию выше.

running->ApplicationReadyEvent

Связанные слушатели относятся к описанию выше.

BackgroundPreinitializer&DelegatingApplicationListener

Эти два проходят через весь процесс, и здесь они объясняются отдельно:

  • BackgroundPreinitializer: для некоторых трудоемких задач используйте фоновый поток, чтобы запустить их как можно раньше, чтобы начать выполнение инициализации, чтоSpringBootповедение по умолчанию. Эти действия по инициализации также можно назвать предварительной инициализацией. Вы можете установить свойства системы,spring.backgroundpreinitializer.ignoreзаtrueЭтот механизм можно отключить. Когда этот механизм отключен, соответствующие задачи инициализации выполняются в потоке переднего плана.
  • DelegatingApplicationListener: прослушивает события приложения и передает эти события приложения свойствам среды.context.listener.classesуказанные слушатели.

резюме

Уже,SpringBootМатериалы, связанные с событием, закончились. Эта статья изSpringApplicationRunListenerНачнем с этого класса, а затем представимSpringBootСобытие, запустившее процесс, и жизненный цикл события. Наконец представилSpringBootЭти встроенные прослушиватели соответствуют различным этапам процесса запуска.

В начале нового года поздравляю всех с Новым годом!

Ссылаться на