设计模式-观察者模式
经典实现方式
// 消息类
@Data
@AllArgsConstructor
public class Message {
Object msg;
}
// 被观察者接口
public interface Subject {
// 添加观察者
void registerObserver(Observer observer);
// 删除观察者
void removeObserver(Observer observer);
// 通知所有观察者
void notifyObservers(Message msg);
}
// 观察者接口
public interface Observer {
// 观察者做后续的动作
void update(Message msg);
}
// 实现被观察者接口
public class MySubject implements Subject {
private List<Observer> observers = new ArrayList<Observer>();
public void registerObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void notifyObservers(Message msg) {
for (Observer observer : observers) {
observer.update(msg);
}
}
}
// 实现观察者接口
public class MyObserver implements Observer {
public void update(Message msg) {
System.out.println("接受到消息:" + msg);
System.out.println("做后续业务...");
}
}
// 测试
public class Main {
public static void main(String[] args) {
MySubject mySubject = new MySubject();
MyObserver myObserver = new MyObserver();
mySubject.registerObserver(myObserver);
mySubject.notifyObservers(new Message("发送消息"));
}
}
好处在哪?例如服务A处理某个业务逻辑,并在最后调用notifyObservers方法,而观察者未来可能新增,这样只需要新建一个类实现Observer接口,并注册到Subject中即可。
可以发现以上的实现方式是同步阻塞的,且不能跨进程调用
主要修改notifyObservers的部分:
// 1. 新开一个线程
public void notifyObservers(Message msg) {
for (Observer observer : observers) {
new Thread(() -> {
observer.update(msg);
}).start();;
}
}
// 2. 使用一个线程池
public void notifyObservers(Message msg) {
// 当然线程池的初始化肯定不能在这里,只是为了演示方便
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (Observer observer : observers) {
executorService.submit(() -> {
observer.update(msg);
});
}
}
这种实现方式的弊端:不能同步和异步之间灵活切换,异步模块不能复用,例如实现其他业务时也需要异步的功能
实现一个简易的EventBus
关键点:
- 注册。拿到观察者的类对象,通过反射找到所有加了@Subscribe注解的方法,通过参数类型来建立[注册表]
- 发消息。通过[注册表]来确定我要给那个观察者发事件,同时观察者的哪些方法要执行。
知道了关键点,其实实现就比较容易了。
@Target(ElementType.METHOD) // 还有TYPE,代表注解的作用目标为类、接口、枚举类
@Retention(RetentionPolicy.RUNTIME) // 还有SOURCE
@Documented
public @interface Subscribe {
}
/**
* 该类用来表示被@Subscribe注解标记的方法,target为观察者类,method为方法
*/
public class ObserverAction {
private Object target;
private Method method;
public ObserverAction(Object target, Method method) {
// 判空,这里为了简单起见就不写了
this.target = target;
this.method = method;
this.method.setAccessible(true);
}
public void execute(Object event) {
try {
method.invoke(target, event);
} catch (InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
public class ObserverRegistry {
private ConcurrentMap<Class<?>, CopyOnWriteArraySet<ObserverAction>> registry =
new ConcurrentHashMap<>();
/**
* 注册观察者
*
* @param observer 观察者
* @author: optimjie
* @date: 2023-08-15 11:14
*/
public void register(Object observer) {
Map<Class<?>, Collection<ObserverAction>> observerActions = findAllObserverActions(observer);
for (Map.Entry<Class<?>, Collection<ObserverAction>> entry : observerActions.entrySet()) {
Class<?> eventType = entry.getKey();
Collection<ObserverAction> eventActions = entry.getValue();
CopyOnWriteArraySet<ObserverAction> registeredEventActions = registry.get(eventType);
if (registeredEventActions == null) {
registry.putIfAbsent(eventType, new CopyOnWriteArraySet<>());
registeredEventActions = registry.get(eventType);
}
registeredEventActions.addAll(eventActions);
}
}
public List<ObserverAction> getMatchedObserverActions(Object event) {
List<ObserverAction> matchedObservers = new ArrayList<>();
Class<?> postedEventType = event.getClass();
for (Map.Entry<Class<?>, CopyOnWriteArraySet<ObserverAction>> entry : registry.entrySet()) {
Class<?> eventType = entry.getKey();
Collection<ObserverAction> eventActions = entry.getValue();
if (postedEventType.isAssignableFrom(eventType)) {
matchedObservers.addAll(eventActions);
}
}
return matchedObservers;
}
/**
* 返回观察者 类型 --> List<ObserverAction> 的map
*
* @param observer 观察者
* @return java.util.Map<java.lang.Class<?>
* @return java.util.Collection<com.optimjie.design.patterns.observe.eventbus.ObserverAction>>
* @author: optimjie
* @date: 2023-08-15 11:15
*/
private Map<Class<?>, Collection<ObserverAction>> findAllObserverActions(Object observer) {
// 定义返回值
Map<Class<?>, Collection<ObserverAction>> observerActions = new HashMap<>();
// 获取观察者的类对象
Class<?> clazz = observer.getClass();
// 遍历所有加了@Subscribe注解的方法
for (Method method : getAnnotatedMethods(clazz)) {
Class<?>[] parameterTypes = method.getParameterTypes();
// 这里是根据方法的第一个参数来区分事件,而且是通过参数的类型来区分
Class<?> eventType = parameterTypes[0];
if (!observerActions.containsKey(eventType)) {
observerActions.put(eventType, new ArrayList<>());
}
observerActions.get(eventType).add(new ObserverAction(observer, method));
}
return observerActions;
}
/**
* 获取所有加了@Subscribe注解的方法
*
* @param clazz
* @return java.util.List<java.lang.reflect.Method>
* @author: optimjie
* @date: 2023-08-15 11:24
*/
private List<Method> getAnnotatedMethods(Class<?> clazz) {
List<Method> annotatedMethods = new ArrayList<>();
// 遍历该类的所有方法
for (Method method : clazz.getDeclaredMethods()) {
// 找到加了@Subscribe注解的方法
if (method.isAnnotationPresent(Subscribe.class)) {
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 0) {
System.out.println("at least one param");
} else {
annotatedMethods.add(method);
}
}
}
return annotatedMethods;
}
}
public class EventBus {
private Executor executor;
private ObserverRegistry registry = new ObserverRegistry();
public EventBus() {
this(MoreExecutors.directExecutor());
}
protected EventBus(Executor executor) {
this.executor = executor;
}
public void register(Object object) {
registry.register(object);
}
public void post(final Object event) {
List<ObserverAction> observerActions = registry.getMatchedObserverActions(event);
for (final ObserverAction observerAction : observerActions) {
executor.execute(() -> {
observerAction.execute(event);
});
}
}
}
public class AsyncEventBus extends EventBus {
public AsyncEventBus(Executor executor) {
super(executor);
}
}
public class Main {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
EventBus eventBus = new AsyncEventBus(executorService);
MyObserver myObserver = new MyObserver();
eventBus.register(myObserver);
eventBus.post(1L);
}
static class MyObserver {
@Subscribe
public void handle(Long id) {
System.out.println("接受到id:" + id);
System.out.println("做后续业务...");
}
@Subscribe
public void otherHandle(Long id) {
System.out.println("接受到id:" + id);
System.out.println("做后续业务...");
}
}
}
Spring中事件监听是如何实现的?
看原理前先看看如何使用【2】
/**
* 事件
*
* @author: optimjie
* @date: 2023-08-15 13:43
*/
public class MyEventModel extends ApplicationEvent {
public MyEventModel(Object source) {
super(source);
}
}
/**
* 事件监听器
*
* @author: optimjie
* @date: 2023-08-15 13:43
*/
@Component
public class MyEventListener {
@EventListener
public void handleEvent(MyEventModel myEventModel){
System.out.println("收到消息:" + myEventModel.getSource());
System.out.println("执行后续业务逻辑...");
}
}
/**
* 业务处理,一般在某个方法结束最后发事件,来完成后续的动作
*
* @author: optimjie
* @date: 2023-08-15 13:43
*/
@Service
public class MyService {
private final ApplicationEventPublisher eventPublisher;
public MyService(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
public void beforePublish() {
MyEventModel myEventModel = new MyEventModel("消息");
eventPublisher.publishEvent(myEventModel);
}
}
/**
* 包扫描
*
* @author: optimjie
* @date: 2023-08-15 13:44
*/
@ComponentScan("com.optimjie.design.patterns.observe.spring")
@Configuration
public class SpringConfig {
}
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
MyService myService = context.getBean(MyService.class);
myService.beforePublish();
}
}
重要的四个类或者接口 :
- ApplicationEvent,事件对象,继承至JDK的类EventObject,可以携带事件的时间戳
- 类比上面
eventBus.post(1L);
中的1L
- 类比上面
- ApplicationListener,事件监听器,继承至JDK的接口EventListener,该接口被所有的事件监听器实现,比如支持指定顺序的。实现类:ApplicationEventMulticaster
- 类比上面的MyObserver
- ApplicationEventMulticaster,事件管理者,管理监听器和发布事件,ApplicationContext通过委托ApplicationEventMulticaster来 发布事件
- 类比上面的ObserverRegistry,管理事件
- ApplicationEventPublisher,事件发布者,该接口封装了事件有关的公共方法,作为ApplicationContext的超级街廓,也是委托 ApplicationEventMulticaster完成事件发布
- 类比EventBus.post
和EventBus不能一一对应起来,但是基本的思想都是类似的。
说明
===================================
仅作为校招时的《个人笔记》,详细内容请看【参考】部分
===================================
参考
- 极客时间《设计模式之美》
- https://www.cnblogs.com/admol/p/14036564.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!