Spring IoC контейнер: дополнительные возможности ApplicationContext, стандартные и специальные события
Обработка событий в ApplicationContext обеспечивается через класс ApplicationEvent и интерфейс ApplicationListener. Если bean-компонент, реализующий интерфейс ApplicationListener, развертывается в контексте, каждый раз, когда ApplicationEvent публикуется в ApplicationContext, этот bean-компонент получает уведомление. По сути, это стандартный шаблон проектирования Observer.
Начиная с Spring 4.2, инфраструктура событий была значительно улучшена и предлагает модель на основе аннотаций, а также возможность публиковать любое произвольное событие (то есть объект, который не обязательно является наследником ApplicationEvent). Когда такой объект публикуется, Spring упаковывает его в событие для вас.
Ниже описаны стандартные события, которые предоставляет Spring:
ContextRefreshedEvent
Публикуется при инициализации или обновлении ApplicationContext (например, с помощью метода refresh() в интерфейсе ConfigurableApplicationContext). Здесь "инициализировано" означает, что все bean-компоненты загружены, bean-компоненты постпроцессора обнаружены и активированы, синглтоны созданы заранее и объект ApplicationContext готов к использованию. Пока контекст не был закрыт, обновление может запускаться несколько раз при условии, что выбранный ApplicationContext действительно поддерживает такие "горячие" обновления. Например, XmlWebApplicationContext поддерживает горячие обновления, а GenericApplicationContext - нет.
ContextStartedEvent
Публикуется при запуске ApplicationContext с помощью метода start() в интерфейсе ConfigurableApplicationContext. Здесь "запущен" означает, что все компоненты жизненного цикла получают явный сигнал запуска. Обычно этот сигнал используется для перезапуска bean-компонентов после явной остановки, но он также может использоваться для запуска компонентов, которые не были настроены для автозапуска (например, компонентов, которые еще не были запущены при инициализации).
ContextStoppedEvent
Публикуется, когда ApplicationContext останавливается с помощью метода stop() в интерфейсе ConfigurableApplicationContext. Здесь "остановлено" означает, что все компоненты жизненного цикла получают явный сигнал остановки. Остановленный контекст можно перезапустить с помощью вызова start().
ContextClosedEvent
Публикуется, когда ApplicationContext закрывается с помощью метода close() в интерфейсе ConfigurableApplicationContext или через обработчик завершения работы JVM. Здесь "закрыто" означает, что все singleton beans будут уничтожены. После закрытия контекста срок его службы истекает, и его нельзя обновить или перезапустить.
RequestHandledEvent
Веб-событие, сообщающее всем bean-компонентам, что HTTP-запрос был обработан. Это событие публикуется после выполнения запроса. Это событие применимо только к веб-приложениям, использующим DispatcherServlet Spring.
ServletRequestHandledEvent
Подкласс RequestHandledEvent, который добавляет контекстную информацию, специфичную для сервлета.
Вы также можете создавать и публиковать свои собственные события. В следующем примере показан простой класс, расширяющий базовый класс Spring ApplicationEvent:
Java
public class BlockedListEvent extends ApplicationEvent {
private final String address;
private final String content;
public BlockedListEvent(Object source, String address, String content) {
super(source);
this.address = address;
this.content = content;
}
// другие методы...
}
Kotlin
class BlockedListEvent(source: Any,
val address: String,
val content: String) : ApplicationEvent(source)
Чтобы опубликовать настраиваемое событие ApplicationEvent, вызовите метод publishEvent() для ApplicationEventPublisher. Обычно это делается путем создания класса, реализующего ApplicationEventPublisherAware, и регистрации его как bean-компонента Spring. В следующем примере показан такой класс:
Java
public class EmailService implements ApplicationEventPublisherAware {
private List
Kotlin
class EmailService : ApplicationEventPublisherAware {
private lateinit var blockedList: List
Во время настройки контейнер Spring определяет, что EmailService реализует ApplicationEventPublisherAware, и автоматически вызывает setApplicationEventPublisher(). На самом деле переданный параметр - это сам контейнер Spring. Вы взаимодействуете с контекстом приложения через его интерфейс ApplicationEventPublisher.
Чтобы получить настраиваемый ApplicationEvent, вы можете создать класс, реализующий ApplicationListener, и зарегистрировать его как bean-компонент Spring. В следующем примере показан такой класс:
Java
public class BlockedListNotifier implements ApplicationListener
Kotlin
class BlockedListNotifier : ApplicationListener
Обратите внимание, что ApplicationListener обычно параметризуется типом вашего настраиваемого события (BlockedListEvent в предыдущем примере). Это означает, что метод onApplicationEvent() может оставаться типобезопасным, избегая необходимости в понижающем преобразовании. Вы можете зарегистрировать столько слушателей событий, сколько захотите, но обратите внимание, что по умолчанию слушатели событий получают события синхронно. Это означает, что метод publishEvent() блокируется до тех пор, пока все слушатели не закончат обработку события. Одно из преимуществ этого синхронного и однопоточного подхода заключается в том, что, когда слушатель получает событие, он работает в контексте транзакции издателя, если контекст транзакции доступен.
В следующем примере показаны определения bean-компонентов, используемые для регистрации и настройки каждого из вышеуказанных классов:
<bean id="emailService" class="example.EmailService">
<property name="blockedList">
<list>
<value>known.spammer@example.org</value>
<value>known.hacker@example.org</value>
<value>john.doe@example.org</value>
</list>
</property>
</bean>
<bean id="blockedListNotifier" class="example.BlockedListNotifier">
<property name="notificationAddress" value="blockedlist@example.org"/>
</bean>
Собирая все вместе, когда вызывается метод sendEmail() bean-компонента emailService, если есть какие-либо сообщения электронной почты, которые следует заблокировать, публикуется настраиваемое событие типа BlockedListEvent. Bean-компонент blockedListNotifier регистрируется как ApplicationListener и получает событие BlockedListEvent, после чего он может уведомить соответствующие стороны.
Механизм событий Spring разработан для простой связи между компонентами Spring в одном контексте приложения. Однако для более сложных потребностей интеграции предприятия отдельно поддерживаемый проект Spring Integration обеспечивает полную поддержку для создания облегченных, шаблонно-ориентированных, управляемых событиями архитектур, основанных на хорошо известной модели программирования Spring.
Читайте также:
- Spring IoC контейнер: дополнительные возможности ApplicationContext
- Spring IoC контейнер: дополнительные возможности ApplicationContext, интернационализация с использованием MessageSource
- Spring IoC контейнер: абстракция Environment, регистрация LoadTimeWeaver
Комментарии
Отправить комментарий