Главная » Spring » Уменьшение связности с использованием событий Spring

0

Внедрение зависимостей является в Spring основным способом ослабления связей между прикладными объектами, но это не един- ственный путь. Еще одним способом взаимодействия объектов явля- ются публикация и обработка событий. Генерируя события, объекты могут взаимодействовать с другими объектами, даже не зная, какие объекты принимают их. Более того, объект, принимающий события, может реагировать на них, не имея представления о том, кто гене- рирует эти события.

Такие взаимодействия, основанные на событиях, напоминают ра- диостанцию и ее аудиторию слушателей, как показано на рис. 3.8. Радиоприемники не подключены непосредственно к радиостанции, и радиостанция не знает о настройках радиоприемников. Тем не

Рис. 3.8. Источник событий напоминает радиостанцию, вещающую о событиях для своих слушателей. Источник событий и приемники полностью отделены друг от друга

менее радиостанция оказывается в состоянии вещать передачи для своих слушателей.

В Spring любой компонент в контейнере может быть приемником или источником событий, или и тем, и другим. Посмотрим, как соз- давать компоненты, участвующие в событиях, и начнем с компонен- тов, генерирующих (или публикующих) события.

Публикация событий

Представьте, что в системе регистрации колледжа необходимо предусмотреть возможность извещения одного или более объектов приложения, что некоторый студент подписался на курс и, как след- ствие, курс оказался набран полностью. При этом, возможно, вы за- хотите автоматически объявить набор на другой курс.

Сначала определим собственное событие, такое как CourseFullEvent:

public class CourseFullEvent extends ApplicationEvent { private  Course  course;

public  CourseFullEvent(Object  source,  Course  course)  { super(source);

this.course   =   course;

}

public Course getCourse() { return   course;

}

}

Далее необходимо опубликовать событие. Интерфейс Application- Context имеет метод publishEvent(), позволяющий публиковать собы- тия ApplicationEvents. Любой приемник событий ApplicationListener, зарегистрировавшийся в контексте приложения, будет получать со- бытие в виде вызова метода onApplicationEvent():

ApplicationContext  context  =  …; Course course = …;

context.publishEvent(new CourseFullEvent(this, course));

К сожалению, чтобы иметь возможность публиковать (посылать) события, компоненты должны иметь доступ к контексту приложе- ния ApplicationContext. Это означает, что компоненты должны знать, в каком контейнере они выполняются. Как сделать так, чтобы ком-

поненты знали, в каком контейнере они действуют, будет показано в разделе 3.5.6.

Скажите, что произойдет с событием, сгенерированным источни- ком, которое никто не примет? Я оставляю этот философский во- прос вам на осмысление. А сейчас обеспечим наличие компонентов, принимающих события, чтобы они не остались без внимания.

Прием событий

В дополнение к событиям, которые генерируются компонентами, фреймворк Spring сам генерирует несколько событий в течение вре- мени жизни приложения. Все эти события являются подклассами абстрактного класса  org.springframework.context.ApplicationEvent.  Ни- же представлены три таких события:

# ContextClosedEvent – генерируется при закрытии контекста при-

ложения;

# ContextRefreshedEvent – генерируется после инициализации или обновления контекста приложения;

#  RequestHandledEvent – генерируется в контексте веб-приложения

после обработки запроса.

По большей части эти события генерируются, чтобы… м-м-м… э-э-э.., в общем генерируются. Большинство компонентов понятия не имеют об этих событиях и зачем они были сгенерированы. Но как быть, если компонент должен получать уведомления о событиях в приложении?

Если требуется, чтобы компонент реагировал на события, сгенери- рованные другим компонентом или контейнером, достаточно просто реализовать интерфейс org.springframework.context.ApplicationListener. Для этого следует реализовать метод onApplicationEvent(),отвечающий за реакцию на события:

public   class   RefreshListener   implements   ApplicationListener   { public  void  onApplicationEvent(ApplicationEvent  event)  {

}

}

После этого единственное, что осталось сделать, – сообщить фреймворку Spring о готовности компонента принимать события, зарегистрировав его в контексте компонента:

<bean  id="refreshListener" class="com.springinaction.foo.RefreshListener"/>

Когда контейнер загрузит компоненты в контекст приложения, он обнаружит реализацию интерфейса ApplicationListener и будет помнить, что надо вызывать его метод onApplicationEvent() при по- явлении события.

Единственное, что следует помнить всегда, – события обраба- тываются синхронно. Поэтому следует позаботиться, чтобы любые события обрабатывались быстро. В противном случае это отрица- тельно скажется на производительности приложения.

Как упоминалось выше, чтобы генерировать события, компонент должен знать о контейнере приложения. Даже если объект не гене- рирует никаких событий, все равно может потребоваться разработать компонент, обладающий доступом к контексту приложения. Посмот- рим далее, как создавать компоненты, со ссылками на их контейнер.

Источник:   Уоллс К., Spring в действии. – М.: ДМК Пресс, 2013. – 752 с.: ил.

По теме:

  • Комментарии