Эта статья участвовала в третьем этапе курса «High Yield Update» тренировочного лагеря для создателей Nuggets. Подробнее см.:Dig Li Project | Идет третий этап тренировочного лагеря создателя, «написание» личного влияния.
Spring предоставляет очень удобный механизм обработки событий, включая класс событий ApplicationEvent и класс прослушивателя событий ApplicationListener. Он реализует режим дизайнера.Если компонент, реализующий интерфейс ApplicationListener, развернут в контейнере Spring, компонент будет получать уведомление каждый раз, когда ApplicationEvent публикуется в ApplicationContext.
Начиная с Spring 4.2, предоставляются события на основе аннотаций, то есть объект события не обязательно должен быть расширен из ApplicationEvent. Spring автоматически инкапсулирует его в объект события.
Ниже приведено стандартное описание события Spring:
Event | объяснять |
---|---|
ContextRefreshedEvent | Отправляется, когда ApplicationContext инициализируется или обновляется (например, с помощью метода refresh() в интерфейсе ConfigurableApplicationContext). Здесь «инициализация» означает, что все bean-компоненты загружены, постпроцессорные bean-компоненты обнаружены и активированы, синглтон предварительно создан и объект ApplicationContext готов к использованию. Обновления могут запускаться несколько раз, пока контекст не закрыт, если выбранный ApplicationContext действительно поддерживает такие «горячие» обновления. Например, XMLWebApplicationContext поддерживает горячее обновление, а GenericApplicationContext — нет. |
ContextStartedEvent | Публикуется, когда ApplicationContext запускается с помощью метода start() в настраиваемом интерфейсе ApplicationContext. Здесь «старт» означает, что все bean-компоненты жизненного цикла получают явный стартовый сигнал. Обычно этот сигнал используется для перезапуска bean-компонентов после явной остановки, но его также можно использовать для запуска компонентов, которые не были настроены на автоматический запуск (например, компоненты, которые не были запущены при инициализации). |
ContextStoppedEvent | Публикуется, когда ApplicationContext останавливается с помощью метода stop() в настраиваемом интерфейсе ApplicationContext. Здесь «остановлено» означает, что все bean-компоненты жизненного цикла получают явный сигнал остановки. Остановленный контекст можно перезапустить вызовом start(). |
ContextClosedEvent | Публикуется, когда ApplicationContext закрывается с помощью метода close() в настраиваемом интерфейсе ApplicationContext. Здесь «закрыто» означает, что все одноэлементные компоненты уничтожены. Замкнутая среда достигает конца жизни. Невозможно обновить или перезапустить. |
RequestHandledEvent | Веб-событие, которое сообщает всем bean-компонентам, что HTTP-запросы были обслужены. Это событие публикуется после выполнения запроса. Это событие доступно только для веб-приложений, использующих DispatcherServlet Spring. |
Событие на основе наследования
Вы также можете настроить событие, ниже приведен пример наследования ApplicationEvent:
public class BlackListEvent extends ApplicationEvent {
private final String address;
private final String content;
public BlackListEvent(Object source, String address, String content) {
super(source);
this.address = address;
this.content = content;
}
}
Чтобы опубликовать пользовательское событие ApplicationEvent, вызовите метод PublishEvent() в ApplicationEventPublisher. Обычно это достигается путем реализации интерфейса ApplicationEventPublisherAware следующим образом:
public class EmailService implements ApplicationEventPublisherAware {
private List<String> blackList;
private ApplicationEventPublisher publisher;
public void setBlackList(List<String> blackList) {
this.blackList = blackList;
}
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
public void sendEmail(String address, String content) {
if (blackList.contains(address)) {
publisher.publishEvent(new BlackListEvent(this, address, content));
return;
}
}
}
Во время настройки контейнер Spring обнаруживает, что EmailService реализует ApplicationEventPublisherAware, и автоматически вызывает setApplicationEventPublisher(). На самом деле переданный параметр — это сам контейнер Spring. Вы взаимодействуете с контекстом приложения через его интерфейс applicationEventPublisher.
Чтобы получить пользовательское событие applicationEvent, вы можете создать класс, реализующий applicationListener, и зарегистрировать его как SpringBean. В следующем примере показан такой класс:
public class BlackListNotifier implements ApplicationListener<BlackListEvent> {
private String notificationAddress;
public void setNotificationAddress(String notificationAddress) {
this.notificationAddress = notificationAddress;
}
public void onApplicationEvent(BlackListEvent event) {
// notify appropriate parties via notificationAddress...
}
}
Здесь используется универсальный BlackListEvent ApplicationListener. Означает, что метод onApplicationEvent() может оставаться типобезопасным, избегая необходимости какого-либо приведения вниз.
Однако обратите внимание, что прослушиватели событий по умолчанию получают события синхронно. Это означает, что метод publishEvent() будет заблокирован до тех пор, пока все слушатели не закончат обработку события.
Ниже приведен пример регистрации и настройки bean-компонента:
<bean id="emailService" class="example.EmailService">
<property name="blackList">
<list>
<value>known.spammer@example.org</value>
<value>known.hacker@example.org</value>
<value>john.doe@example.org</value>
</list>
</property>
</bean>
<bean id="blackListNotifier" class="example.BlackListNotifier">
<property name="notificationAddress" value="blacklist@example.org"/>
</bean>
Механизм событий Spring разработан для простой связи между SpringBeans в одном и том же контексте приложения. Для более сложных потребностей корпоративной интеграции можно использовать модель AMQP Spring Integration.
События на основе аннотаций
Начиная с Spring 4.2, вы можете использовать аннотацию EventListener для регистрации прослушивателей событий в любом общедоступном методе управляемого компонента. Программу BlackListNotifier можно переписать следующим образом:
public class BlackListNotifierAnnotation {
private String notificationAddress;
public void setNotificationAddress(String notificationAddress) {
this.notificationAddress = notificationAddress;
}
@EventListener
public void processBlackListEvent(BlackListEvent event) {
// notify appropriate parties via notificationAddress...
}
}
Если ваш метод должен прослушивать несколько событий или вы хотите определить его без каких-либо параметров, вы также можете указать тип события в самой аннотации. В следующем примере показано, как это сделать:
@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
public void handleContextStart() {
}
Также можно добавить дополнительную фильтрацию во время выполнения, используя условный атрибут аннотации, определяющий выражение spEL, которое должно соответствовать методу, фактически вызывающему конкретное событие.
В следующем примере показано, как переопределить уведомитель, чтобы он вызывался только тогда, когда свойство содержимого события равно my-event:
@EventListener(condition = "#blEvent.content == 'my-event'")
public void processBlackListSPELEvent(BlackListEvent blEvent) {
// notify appropriate parties via notificationAddress...
}
В следующей таблице перечислены элементы, доступные в контексте, чтобы их можно было использовать для условной обработки событий:
name | Location | описывать | пример |
---|---|---|---|
Event | root object | реальное событие приложения | #root.event |
Arguments array | root object | вызвать параметры цели | #root.args[0] |
Argument name | evaluation context | Имя любого параметра метода. Если по какой-либо причине имя недоступно (например, из-за отсутствия отладочной информации), имя параметра также можно использовать в #a, где #arg представляет индекс параметра (начиная с 0). | #blEvent или #a0 (также можно использовать #p0 или #p) |
асинхронный слушатель
Если вы хотите, чтобы определенный прослушиватель обрабатывал события асинхронно, вы можете повторно использовать обычную поддержку @Async. Вот пример @Async:
@Async
@EventListener
public void processBlackListEvent(BlackListEvent event) {
// notify appropriate parties via notificationAddress...
}
СлушателиСортировать
Если вам нужно вызвать один слушатель перед другим, вы можете добавить аннотацию @order к объявлению метода следующим образом:
@EventListener
@Order(12)
public void processBlackListEvent(BlackListEvent event) {
// notify appropriate parties via notificationAddress...
}
Примеры этой статьи могут относиться к:event
Дополнительные руководства см.блог флайдина