EventBus Class
EventBus очень гибок и может использоваться как одиночный, или приложение может иметь несколько экземпляров для размещения передачи событий в разных контекстах. EventBus будет отправлять все события последовательно, поэтому важно, чтобы методы обработки событий были легкими. Если вам нужно выполнить более сложную обработку в обработчиках событий, есть другой вариант EventBus, AsyncEventBus. Функция AsyncEventBus идентична по функциональности, но принимает ExecutorService в качестве аргумента конструктора, чтобы обеспечить асинхронную диспетчеризацию событий.
Подписка на события
Объект подписывается на события, выполняя следующие действия:
- Определите открытый метод, который принимает один аргумент желаемого типа события, и поместите аннотацию @Subscribe для этого метода.
- Зарегистрируйтесь в EventBus, передав экземпляр объекта методу EventBus.register.
Вот краткий пример с деталями, опущенными для ясности:
01
02
03
04
05
06
07
08
09
10
|
public class PurchaseSubscriber { @Subscribe public void handlePurchaseEvent(PurchaseEvent event) { ..... } ..... EventBus eventBus = new EventBus(); PurchaseSubscriber purchaseSubscriber = new PurchaseSubscriber(); eventBus.register(purchaseSubscriber); |
Есть еще одна аннотация, которую можно использовать вместе с @Subscribe, и это @AllowConcurrentEvents. @AllowConcurrentEvents помечает метод-обработчик как потокобезопасный, поэтому EventBus (скорее всего, AsyncEventBus) потенциально может вызывать обработчик событий из одновременных потоков. Одна интересная вещь, которую я обнаружил в модульном тестировании, заключается в том, что если метод-обработчик не имеет аннотации @AllowConcurrentEvents, он будет вызывать обработчики для события последовательно, даже при использовании AsyncEventBus. Важно отметить, что @AllowConcurrentEvents не будет помечать метод как обработчик событий, аннотация @Subscribe все еще должна присутствовать. Наконец, метод обработки событий должен иметь один и только один параметр, иначе IllegalArgumentException будет выброшен при регистрации объекта в EventBus.
Издательские события
Публикация событий с помощью EventBus также проста. В разделе кода, куда вы хотите отправить уведомление о событии, вызовите EventBus.post, и все подписчики, зарегистрированные для этого объекта события, будут уведомлены.
1
2
3
4
5
|
public void handleTransaction(){ purchaseService.purchase(item,amount); eventBus.post( new CashPurchaseEvent(item,amount)); .... } |
Хотя это может быть очевидно, важно, чтобы подписывающиеся и публикующие классы совместно использовали один и тот же экземпляр EventBus, и было бы целесообразно использовать Guice или Spring для управления зависимостями.
Подробнее о обработчиках событий
Очень мощная особенность EventBus заключается в том, что вы можете сделать ваши обработчики такими же точными или точными, как необходимо. EventBus будет вызывать зарегистрированных подписчиков для всех подтипов и реализованных интерфейсов размещенного объекта события. Например, для обработки любых событий можно создать обработчик событий, который принимает параметр типа Object. Чтобы обрабатывать только единичные события, создайте обработчик, который очень специфичен для типа. Чтобы проиллюстрировать это, рассмотрим следующую простую иерархию событий:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public abstract class PurchaseEvent { String item; public PurchaseEvent(String item){ this .item = item; } } public class CashPurchaseEvent extends PurchaseEvent { int amount; public CashPurchaseEvent(String item, int amount){ super (item); this .amount = amount; } } public class CreditPurchaseEvent extends PurchaseEvent { int amount; String cardNumber; public CreditPurchaseEvent(String item, int amount, String cardNumber){ super (item); this .amount = amount; this .cardNumber = cardNumber; } } |
Вот соответствующие классы обработки событий:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
//Would only be notified of Cash purchase events public class CashPurchaseSubscriber { @Subscribe public void handleCashPurchase(CashPurchaseEvent event){ ... } } //Would only be notified of credit purchases public class CreditPurchaseSubscriber { @Subscribe public void handleCreditPurchase(CreditPurchaseEvent event) { .... } } //Notified of any purchase event public class PurchaseSubscriber { @Subscribe public void handlePurchaseEvent(PurchaseEvent event) { ..... } } |
Если необходимо захватить широкий диапазон типов событий, альтернативой может быть наличие более одного метода обработки событий в классе. Наличие нескольких обработчиков может быть лучшим решением, так как вам не придется выполнять какие-либо проверки «instanceof» для параметра объекта события. Вот простой пример из моего модульного теста:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public class MultiHandlerSubscriber { List<CashPurchaseEvent> cashEvents = new ArrayList<ashPurchaseEvent>(); List<CreditPurchaseEvent> creditEvents = new ArrayList<CreditPurchaseEvent>(); List<SimpleEvent> simpleEvents = new ArrayList<SimpleEvent>(); public MultiHandlerSubscriber(EventBus eventBus){ eventBus.register( this ); } @Subscribe public void handleCashEvents(CashPurchaseEvent event){ cashEvents.add(event); } @Subscribe public void handleCreditEvents(CreditPurchaseEvent event){ creditEvents.add(event); } @Subscribe public void handleSimpleEvents(SimpleEvent event){ simpleEvents.add(event); } .... |
тестирование
Поскольку обработчики событий являются просто простыми методами, их можно легко протестировать, создав экземпляр EventBus в тестовом примере или смоделировав EventBus, передав соответствующий объект события. При работе с EventBus я обнаружил, что очень легко:
- Забудьте зарегистрировать подписывающийся объект в EventBus
- Не забудьте добавить аннотацию @Subscribe.
Если кажется, что обработчик событий не вызывается, сначала проверьте эти две ошибки.
Полезной техникой отладки является подписка на класс DeadEvent. EventBus обернет любое опубликованное событие без обработчиков в экземпляре DeadEvent. DeadEvent предоставляет метод getEvent, который возвращает исходный объект события.
Вывод
Класс Guava EventBus предоставляет привлекательную и полезную альтернативу стандартному механизму обработки событий Java. Есть надежда, что читатель найдет EventBus таким же полезным, как и я. Как всегда комментарии и предложения приветствуются.
Ресурсы
Ссылка: Программирование событий с помощью Google Guava EventBus от нашего партнера по JCG Билла Бекака в блоге Randomечанище по кодированию .