Основное содержание этой статьи:
- Знакомство с шаблоном наблюдателя
- Публикация/подписка Пример официальной учетной записи WeChat
- Обзор шаблона наблюдателя
- Типичные применения шаблона Analysis Observer
- Шаблон наблюдателя в интерфейсе наблюдателя, предоставляемом JDK
- Шаблон наблюдателя в Guava EventBus
- Шаблон наблюдателя в модели делегированных событий JDK DEM
- Шаблон наблюдателя в механизме событий Spring ApplicationContext
Для получения дополнительной информации, пожалуйста, посетите мой личный блог:laijianfeng.org
Обратите внимание на общедоступную учетную запись [Xiao Xuanfeng] WeChat и своевременно получайте сообщения в блогах.
Шаблон наблюдателя
Режим наблюдателя — это «суперрежим» в режиме разработки, его применение можно увидеть повсюду, в качестве примера возьмем общедоступную учетную запись WeChat.
Общедоступные учетные записи WeChat делятся на служебные учетные записи, подписные учетные записи и корпоративные учетные записи. Возьмем, к примеру, мой официальный аккаунт. Мой официальный тип аккаунта — это аккаунт с подпиской и имя «Xiao Xuanfeng», который фокусируется на больших данных и совместном использовании серверных технологий Java. В настоящее время в основном нужно делиться учебными заметками и стараться быть «оригинальным», «качественным» и «систематическим». Всякий раз, когда я публикую сообщение в блоге, подписанные пользователи могут получить уведомление вовремя после того, как я опубликую сообщение, и могут легко прочитать его на мобильном телефоне.
Шаблон наблюдателя: определяет отношение зависимости между объектами «один ко многим», так что всякий раз, когда изменяется состояние объекта, связанные с ним зависимые объекты уведомляются и автоматически обновляются. Паттерн Наблюдатель — это поведенческий паттерн объекта.
Псевдонимы для шаблона наблюдателя включают шаблон публикации/подписки, шаблон модели/представления, шаблон источника/слушателя или шаблон зависимых элементов.
Шаблон наблюдателя включает два типа объектов: цель наблюдения и наблюдатель.Цель может иметь любое количество наблюдателей, которые зависят от нее.Как только состояние цели наблюдения изменится, все наблюдатели будут уведомлены.
Роль
Тема: Цель, также известная как субъект, относится к наблюдаемому объекту. Набор наблюдателей определен в цели.Цель наблюдения может принимать любое количество наблюдателей для наблюдения.Он предоставляет ряд методов для добавления и удаления объектов-наблюдателей и определяет метод уведомления notify(). Целевой класс может быть интерфейсом, абстрактным классом или конкретным классом.
БетонТема: конкретная цель является подклассом целевого класса, обычно она содержит данные, которые часто изменяются, и при изменении ее состояния она уведомляет своих различных наблюдателей; в то же время она также реализует абстрактный бизнес, определенный в целевом классе. Логический метод (если есть). Если целевой класс не нуждается в расширении, конкретный целевой класс можно не указывать.
Наблюдатель: Наблюдатель будет реагировать на изменения в объекте наблюдения Наблюдатель обычно определяется как интерфейс, который объявляет метод update() для обновления данных, поэтому его также называют абстрактным наблюдателем.
ConcreteObserver (конкретный наблюдатель): поддерживает ссылку на конкретный целевой объект в конкретном наблюдателе, который хранит соответствующее состояние конкретного наблюдателя, которое должно быть согласовано с состоянием конкретной цели; он реализует метод update(), определенный в абстрактном наблюдателе Observer . Обычно во время реализации вы можете вызвать метод attach() определенного целевого класса, чтобы добавить себя в коллекцию целевого класса или удалить себя из коллекции целевого класса с помощью метода detach().
Пример
Во-первых, вам нужен абонентский интерфейс (наблюдатель), который имеетreceive
способ получения push-уведомлений с официального аккаунта
public interface Subscriber {
int receive(String publisher, String articleName);
}
Затем есть клиент WeChat (конкретный наблюдатель), который реализуетreceive
метод
public class WeChatClient implements Subscriber {
private String username;
public WeChatClient(String username) {
this.username = username;
}
@Override
public int receive(String publisher, String articleName) {
// 接收到推送时的操作
System.out.println(String.format("用户<%s> 接收到 <%s>微信公众号 的推送,文章标题为 <%s>", username, publisher, articleName));
return 0;
}
}
Класс издателя (целевой, наблюдаемый объект), который поддерживает список подписчиков и реализует такие функции, как подписка, отказ от подписки и уведомление всех подписчиков.
public class Publisher {
private List<Subscriber> subscribers;
private boolean pubStatus = false;
public Publisher() {
subscribers = new ArrayList<Subscriber>();
}
protected void subscribe(Subscriber subscriber) {
this.subscribers.add(subscriber);
}
protected void unsubscribe(Subscriber subscriber) {
if (this.subscribers.contains(subscriber)) {
this.subscribers.remove(subscriber);
}
}
protected void notifySubscribers(String publisher, String articleName) {
if (this.pubStatus == false) {
return;
}
for (Subscriber subscriber : this.subscribers) {
subscriber.receive(publisher, articleName);
}
this.clearPubStatus();
}
protected void setPubStatus() {
this.pubStatus = true;
}
protected void clearPubStatus() {
this.pubStatus = false;
}
}
Класс общедоступной учетной записи WeChat (конкретная цель), который обеспечиваетpublishArticles
Метод, используемый для публикации push, когда статья опубликована, вызывает метод уведомления всех подписчиков родительского класса.
public class WeChatAccounts extends Publisher {
private String name;
public WeChatAccounts(String name) {
this.name = name;
}
public void publishArticles(String articleName, String content) {
System.out.println(String.format("\n<%s>微信公众号 发布了一篇推送,文章名称为 <%s>,内容为 <%s> ", this.name, articleName, content));
setPubStatus();
notifySubscribers(this.name, articleName);
}
}
контрольная работа
public class Test {
public static void main(String[] args) {
WeChatAccounts accounts = new WeChatAccounts("小旋锋");
WeChatClient user1 = new WeChatClient("张三");
WeChatClient user2 = new WeChatClient("李四");
WeChatClient user3 = new WeChatClient("王五");
accounts.subscribe(user1);
accounts.subscribe(user2);
accounts.subscribe(user3);
accounts.publishArticles("设计模式 | 观察者模式及典型应用", "观察者模式的内容...");
accounts.unsubscribe(user1);
accounts.publishArticles("设计模式 | 单例模式及典型应用", "单例模式的内容....");
}
}
Результаты следующие, что соответствует ожиданиям: когда официальный аккаунт публикует push-уведомление, пользователи, подписавшиеся на официальный аккаунт, могут вовремя получить push-уведомление.
<小旋锋>微信公众号 发布了一篇推送,文章名称为 <设计模式 | 观察者模式及典型应用>,内容为 <观察者模式的内容...>
用户<张三> 接收到 <小旋锋>微信公众号 的推送,文章标题为 <设计模式 | 观察者模式及典型应用>
用户<李四> 接收到 <小旋锋>微信公众号 的推送,文章标题为 <设计模式 | 观察者模式及典型应用>
用户<王五> 接收到 <小旋锋>微信公众号 的推送,文章标题为 <设计模式 | 观察者模式及典型应用>
<小旋锋>微信公众号 发布了一篇推送,文章名称为 <设计模式 | 单例模式及典型应用>,内容为 <单例模式的内容....>
用户<李四> 接收到 <小旋锋>微信公众号 的推送,文章标题为 <设计模式 | 单例模式及典型应用>
用户<王五> 接收到 <小旋锋>微信公众号 的推送,文章标题为 <设计模式 | 单例模式及典型应用>
Диаграмму классов можно нарисовать следующим образом
Воспользуйтесь этой возможностью, чтобы сделать небольшую акцию, приглашаю всех обратить внимание на мой публичный аккаунт WeChat ^_^
Обзор шаблона наблюдателя
Режим наблюдателяглавное преимуществоследующим образом:
-
Шаблон наблюдателя может реализовывать разделение уровня представления и уровня логики данных, определять стабильный механизм доставки обновлений сообщений и абстрагировать интерфейс обновления, так что различные уровни представления могут действовать как определенные роли наблюдателя.
-
Паттерн Наблюдатель устанавливает абстрактную связь между объектом наблюдения и наблюдателем. Цель наблюдения должна поддерживать только набор абстрактных наблюдателей, не зная своих конкретных наблюдателей. Поскольку объекты наблюдения и наблюдатели не связаны жестко, они могут принадлежать разным уровням абстракции.
-
Режим наблюдателя поддерживает широковещательную связь, и цель наблюдения будет отправлять уведомления всем зарегистрированным объектам-наблюдателям, что упрощает проектирование системы «один ко многим».
-
Режим наблюдателя удовлетворяет требованиям «открытого и закрытого принципа», добавление новых конкретных наблюдателей не требует изменения исходного кода системы, а также очень удобно добавлять новые цели наблюдения, когда нет связи между конкретными наблюдателями и наблюдением. цели. .
Режим наблюдателяглавный недостатокследующим образом:
-
Если наблюдаемый объект имеет много прямых и косвенных наблюдателей, потребуется много времени, чтобы уведомить всех наблюдателей.
-
Если между наблюдателем и целью наблюдения существует циклическая зависимость, цель наблюдения инициирует циклический вызов между ними, что может привести к сбою системы.
-
Шаблон наблюдателя не имеет соответствующего механизма, позволяющего наблюдателю узнать, как изменился наблюдаемый целевой объект, а только знать, что наблюдаемая цель изменилась.
Применимая сцена:
-
Абстрактная модель имеет два аспекта, один из которых зависит от другого, и инкапсуляция этих двух аспектов в отдельные объекты позволяет изменять и повторно использовать их независимо друг от друга.
-
Изменение одного объекта приведет к изменению одного или нескольких других объектов, причем неизвестно, сколько объектов изменится или кто эти объекты.
-
В системе необходимо создать цепочку триггеров, поведение объекта A повлияет на объект B, поведение объекта B повлияет на объект C..., вы можете использовать шаблон наблюдателя для создания механизма триггера цепочки.
Типичное применение шаблона наблюдателя
Интерфейс наблюдателя, предоставляемый JDK
Положение шаблона наблюдателя в языке Java очень важно. в JDKjava.util
пакет, обеспечиваетObservable
класс иObserver
интерфейсы, которые формируют поддержку JDK для шаблона Observer.
один из нихObserver
Интерфейс наблюдатель, есть только одинupdate
метод, который вызывается при изменении цели наблюдения, и его код выглядит следующим образом:
public interface Observer {
void update(Observable o, Object arg);
}
Observable
class является целевым классом, по сравнению с нашим примеромPublisher
Классы имеют больше параллелизма и соображений NPE
public class Observable {
private boolean changed = false;
private Vector<Observer> obs = new Vector();
public Observable() {
}
// 用于注册新的观察者对象到向量中
public synchronized void addObserver(Observer var1) {
if (var1 == null) {
throw new NullPointerException();
} else {
if (!this.obs.contains(var1)) {
this.obs.addElement(var1);
}
}
}
// 用于删除向量中的某一个观察者对象
public synchronized void deleteObserver(Observer var1) {
this.obs.removeElement(var1);
}
public void notifyObservers() {
this.notifyObservers((Object)null);
}
// 通知方法,用于在方法内部循环调用向量中每一个观察者的update()方法
public void notifyObservers(Object var1) {
Object[] var2;
synchronized(this) {
if (!this.changed) {
return;
}
var2 = this.obs.toArray();
this.clearChanged();
}
for(int var3 = var2.length - 1; var3 >= 0; --var3) {
((Observer)var2[var3]).update(this, var1);
}
}
// 用于清空向量,即删除向量中所有观察者对象
public synchronized void deleteObservers() {
this.obs.removeAllElements();
}
// 该方法被调用后会设置一个boolean类型的内部标记变量changed的值为true,表示观察目标对象的状态发生了变化
protected synchronized void setChanged() {
this.changed = true;
}
// 用于将changed变量的值设为false,表示对象状态不再发生改变或者已经通知了所有的观察者对象,调用了它们的update()方法
protected synchronized void clearChanged() {
this.changed = false;
}
// 返回对象状态是否改变
public synchronized boolean hasChanged() {
return this.changed;
}
// 返回向量中观察者的数量
public synchronized int countObservers() {
return this.obs.size();
}
}
мы можем использоватьObservable
класс иObserver
интерфейс для повторной реализации примера общедоступной учетной записи WeChat.
Добавить класс уведомленийWechatNotice
, для доставки push-уведомлений
@Data
@AllArgsConstructor
public class WechatNotice {
private String publisher;
private String articleName;
}
затем переписатьWeChatClient
а такжеWeChatAccounts
, соответственно реализуя JDKObserver
Интерфейсы и наследованиеObservable
Добрый
public class WeChatClient implements Observer {
private String username;
public WeChatClient(String username) {
this.username = username;
}
@Override
public void update(Observable o, Object arg) {
//WeChatAccounts weChatAccounts = (WeChatAccounts) o;
WechatNotice notice = (WechatNotice) arg;
System.out.println(String.format("用户<%s> 接收到 <%s>微信公众号 的推送,文章标题为 <%s>", username, notice.getPublisher(), notice.getArticleName()));
}
}
public class WeChatAccounts extends Observable {
private String name;
public WeChatAccounts(String name) {
this.name = name;
}
public void publishArticles(String articleName, String content) {
System.out.println(String.format("\n<%s>微信公众号 发布了一篇推送,文章名称为 <%s>,内容为 <%s> ", this.name, articleName, content));
setChanged();
notifyObservers(new WechatNotice(this.name, articleName));
}
}
Test, отличие от тестового кода в примере заключается в вызываемом методе
public class Test {
public static void main(String[] args) {
WeChatAccounts accounts = new WeChatAccounts("小旋锋");
WeChatClient user1 = new WeChatClient("张三");
WeChatClient user2 = new WeChatClient("李四");
WeChatClient user3 = new WeChatClient("王五");
accounts.addObserver(user1);
accounts.addObserver(user2);
accounts.addObserver(user3);
accounts.publishArticles("设计模式 | 观察者模式及典型应用", "观察者模式的内容...");
accounts.deleteObserver(user1);
accounts.publishArticles("设计模式 | 单例模式及典型应用", "单例模式的内容....");
}
}
Результаты испытаний следующие, и можно обнаружить, что результаты согласуются с примером
<小旋锋>微信公众号 发布了一篇推送,文章名称为 <设计模式 | 观察者模式及典型应用>,内容为 <观察者模式的内容...>
用户<王五> 接收到 <小旋锋>微信公众号 的推送,文章标题为 <设计模式 | 观察者模式及典型应用>
用户<李四> 接收到 <小旋锋>微信公众号 的推送,文章标题为 <设计模式 | 观察者模式及典型应用>
用户<张三> 接收到 <小旋锋>微信公众号 的推送,文章标题为 <设计模式 | 观察者模式及典型应用>
<小旋锋>微信公众号 发布了一篇推送,文章名称为 <设计模式 | 单例模式及典型应用>,内容为 <单例模式的内容....>
用户<王五> 接收到 <小旋锋>微信公众号 的推送,文章标题为 <设计模式 | 单例模式及典型应用>
用户<李四> 接收到 <小旋锋>微信公众号 的推送,文章标题为 <设计模式 | 单例模式及典型应用>
Шаблон наблюдателя в Guava EventBus
в ГуавеEventBus
Он инкапсулирует удобную «модель производства/потребления» и реализует мониторинг регистрации и распределения событий в режиме наблюдателя очень простым способом.
б/у гуаваEventBus
После этого, если вам нужно подписаться на сообщения, вам не нужно реализовывать какой-либо интерфейс, просто добавьте метод слушателя@Subscribe
Просто комментируйте,EventBus
при условииregister
а такжеunregister
методы используются для регистрации и отмены регистрации событий, когдаEventBus
перечислитьpost
метод отправит событие зарегистрированному объекту
Повторите пример, используя Guava
@Data
@AllArgsConstructor
public class WechatNotice {
private String publisher;
private String articleName;
}
public class WeChatClient {
private String username;
public WeChatClient(String username) {
this.username = username;
}
@Subscribe
public void listen(WechatNotice notice) {
System.out.println(String.format("用户<%s> 接收到 <%s>微信公众号 的推送,文章标题为 <%s>", username, notice.getPublisher(), notice.getArticleName()));
}
}
public class WeChatAccounts {
private String name;
private EventBus eventBus;
public WeChatAccounts(String name) {
this.name = name;
this.eventBus = new EventBus();
}
public void publishArticles(String articleName, String content) {
System.out.println(String.format("\n<%s>微信公众号 发布了一篇推送,文章名称为 <%s>,内容为 <%s> ", this.name, articleName, content));
this.eventBus.post(new WechatNotice(this.name, articleName));
}
public void register(WeChatClient weChatClient) {
this.eventBus.register(weChatClient);
}
public void unregister(WeChatClient weChatClient) {
this.eventBus.unregister(weChatClient);
}
}
контрольная работа
public class Test {
public static void main(String[] args) {
WeChatAccounts accounts = new WeChatAccounts("小旋锋");
WeChatClient user1 = new WeChatClient("张三");
WeChatClient user2 = new WeChatClient("李四");
WeChatClient user3 = new WeChatClient("王五");
accounts.register(user1);
accounts.register(user2);
accounts.register(user3);
accounts.publishArticles("设计模式 | 观察者模式及典型应用", "观察者模式的内容...");
accounts.unregister(user1);
accounts.publishArticles("设计模式 | 单例模式及典型应用", "单例模式的内容....");
}
}
Неудивительно, что вывод такой же, как и в двух приведенных выше примерах.
<小旋锋>微信公众号 发布了一篇推送,文章名称为 <设计模式 | 观察者模式及典型应用>,内容为 <观察者模式的内容...>
用户<张三> 接收到 <小旋锋>微信公众号 的推送,文章标题为 <设计模式 | 观察者模式及典型应用>
用户<李四> 接收到 <小旋锋>微信公众号 的推送,文章标题为 <设计模式 | 观察者模式及典型应用>
用户<王五> 接收到 <小旋锋>微信公众号 的推送,文章标题为 <设计模式 | 观察者模式及典型应用>
<小旋锋>微信公众号 发布了一篇推送,文章名称为 <设计模式 | 单例模式及典型应用>,内容为 <单例模式的内容....>
用户<李四> 接收到 <小旋锋>微信公众号 的推送,文章标题为 <设计模式 | 单例模式及典型应用>
用户<王五> 接收到 <小旋锋>微信公众号 的推送,文章标题为 <设计模式 | 单例模式及典型应用>
Для более подробного использования Guava EventBus вы можете самостоятельно проверить соответствующие документы.
Анализ исходного кода Guava EventBus можно посмотреть здесьt.cn/EZzC35B
Шаблон наблюдателя в модели делегированных событий JDK DEM
Во-первых, давайте нажмем кнопку AWT, чтобы прослушать демонстрацию события.
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class MouseEvents {
private Frame frame;
private Button button;
MouseEvents() {
frame = new Frame("点击按钮触发点击事件,控制台将打印日志");
frame.setBounds(300, 200, 600, 300);
frame.setLayout(new FlowLayout());
button = new Button("this is a button");
button.setFont(new Font("Default", 0, 30));
frame.add(button);
dealwithEvent();
frame.setVisible(true);
}
//事件监听器以及处理事件
private void dealwithEvent() {
// 监听窗体关闭事件
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
button.addActionListener(new ActionListener() {
private int eventCount = 1;
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(String.format("动作事件发生 %d 次", eventCount++));
}
});
}
public static void main(String[] args) {
new MouseEvents();
}
}
Запустив основной метод, на рабочем столе появятся следующие панели и кнопки.
кнопкаaddActionListener
Добавьте указанный прослушиватель действий для получения событий действия от этой кнопки.Когда пользователь нажимает или отпускает кнопку мыши на кнопке, JVM генерирует соответствующийActionEvent
объект события типа и вызовет кнопкуfireXXX()
метод (наследуется от Component), внутри этого метода вызов регистрируется на кнопкуActionListener
объектactionPerformed()
метод (то есть класс обработки анонимных событий, который мы реализовали) для обработки события
动作事件发生 1 次
动作事件发生 2 次
动作事件发生 3 次
动作事件发生 4 次
Шаблон наблюдателя в механизме событий Spring ApplicationContext
Механизм событий Spring расширяется от механизма событий java.ApplicationContext
Обработка средних событий выполняетсяApplicationEvent
класс иApplicationListener
предоставляется интерфейсом. Если компонент реализуетApplicationListener
интерфейс и каждый раз публиковался в контейнереApplicationContext
опубликоватьApplicationEvent
событие, компонент будет уведомлен
- ApplicationContext: источник событий, где метод publishEvent() используется для запуска событий контейнера.
- ApplicationEvent: само событие, пользовательские события должны наследовать этот класс и могут использоваться для передачи данных.
- ApplicationListener: интерфейс слушателя событий, бизнес-логика события инкапсулирована в слушателе.
Повторно реализуйте пример, используя механизм событий spring.
@Data
public class WechatNotice extends ApplicationEvent {
private String publisher;
private String articleName;
public WechatNotice(Object source, String publisher, String articleName) {
super(source);
this.publisher = publisher;
this.articleName = articleName;
}
}
public class WeChatClient implements ApplicationListener {
private String username;
public WeChatClient(String username) {
this.username = username;
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof WechatNotice) {
WechatNotice notice = (WechatNotice) event;
System.out.println(String.format("用户<%s> 接收到 <%s>微信公众号 的推送,文章标题为 <%s>", username, notice.getPublisher(), notice.getArticleName()));
}
}
public void setUsername(String username) {
this.username = username;
}
}
public class WeChatAccounts implements ApplicationContextAware {
private ApplicationContext ctx;
private String name;
public WeChatAccounts(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.ctx = applicationContext;
}
public void publishArticles(String articleName, String content) {
System.out.println(String.format("\n<%s>微信公众号 发布了一篇推送,文章名称为 <%s>,内容为 <%s> ", this.name, articleName, content));
ctx.publishEvent(new WechatNotice(this.name, this.name, articleName));
}
}
Создал в каталоге ресурсовspring.xml
файл, заполните следующее
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="WeChatAccounts" class="com.observer.sprintevent.WeChatAccounts" scope="prototype">
<constructor-arg name="name" value=""></constructor-arg>
</bean>
<bean id="WeChatClient1" class="com.observer.sprintevent.WeChatClient">
<constructor-arg name="username" value="张三"></constructor-arg>
</bean>
<bean id="WeChatClient2" class="com.observer.sprintevent.WeChatClient">
<constructor-arg name="username" value="李四"></constructor-arg>
</bean>
<bean id="WeChatClient3" class="com.observer.sprintevent.WeChatClient">
<constructor-arg name="username" value="王五"></constructor-arg>
</bean>
</beans>
контрольная работа
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
WeChatAccounts accounts = (WeChatAccounts) context.getBean("WeChatAccounts");
accounts.setName("小旋锋");
accounts.setApplicationContext(context);
accounts.publishArticles("设计模式 | 观察者模式及典型应用", "观察者模式的内容...");
}
}
Вывод выглядит следующим образом
<小旋锋>微信公众号 发布了一篇推送,文章名称为 <设计模式 | 观察者模式及典型应用>,内容为 <观察者模式的内容...>
用户<张三> 接收到 <小旋锋>微信公众号 的推送,文章标题为 <设计模式 | 观察者模式及典型应用>
用户<李四> 接收到 <小旋锋>微信公众号 的推送,文章标题为 <设计模式 | 观察者模式及典型应用>
用户<王五> 接收到 <小旋锋>微信公众号 的推送,文章标题为 <设计模式 | 观察者模式及典型应用>
в этом примереApplicationContext
Фактический тип объектаClassPathXmlApplicationContext
, из них сpublishEvent
Основной код, относящийся к методу, выглядит следующим образом:
private ApplicationEventMulticaster applicationEventMulticaster;
public void publishEvent(ApplicationEvent event) {
this.getApplicationEventMulticaster().multicastEvent(event);
if (this.parent != null) {
this.parent.publishEvent(event);
}
}
ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {
return this.applicationEventMulticaster;
}
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
if (beanFactory.containsLocalBean("applicationEventMulticaster")) {
this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class);
} else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster);
}
}
один из нихSimpleApplicationEventMulticaster
следующим образом,multicastEvent
Метод в основном заключается в обходеApplicationListener
(Регистрация осуществляется с помощью AbstractApplicationEventMulticaster), используя структуру пула потоков.Executor
выполнять одновременноApplicationListener
изonApplicationEvent
метод, который по существу аналогичен примеру
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
private Executor taskExecutor;
public void multicastEvent(final ApplicationEvent event) {
Iterator var2 = this.getApplicationListeners(event).iterator();
while(var2.hasNext()) {
final ApplicationListener listener = (ApplicationListener)var2.next();
Executor executor = this.getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
public void run() {
listener.onApplicationEvent(event);
}
});
} else {
listener.onApplicationEvent(event);
}
}
}
}
Ссылаться на:
Лю Вэй: Шаблоны проектирования Java Edition
MOOC Java Design Patterns Интенсивный метод отладки + анализ памяти
Простая реализация, управляемая событиями, с помощью гуавы
механизм событий springboot
Рекомендуемое чтение
Шаблоны проектирования | Простые фабричные шаблоны и типовые приложения
Шаблоны проектирования | Шаблоны фабричных методов и типичные приложения
Шаблоны проектирования | Абстрактные фабричные шаблоны и типовые приложения
Шаблоны проектирования | Шаблоны построителей и типичные приложения
Шаблоны проектирования | Шаблоны прототипов и типовые приложения
Шаблоны проектирования | Шаблоны внешнего вида и типичные приложения
Шаблоны проектирования | Шаблоны декораторов и типичные приложения
Шаблоны проектирования | Шаблоны адаптеров и типичные приложения
Шаблоны проектирования | Легковесные шаблоны и типичные приложения
Шаблоны проектирования | Комбинированные шаблоны и типичные приложения
Шаблоны проектирования | Шаблоны методов шаблонов и типичные приложения
Шаблоны проектирования | Шаблоны итераторов и типичные приложения
Шаблоны проектирования | Шаблоны стратегий и типичные приложения
Шаблоны проектирования | Шаблоны Observer и типичные приложения