package com.chuangzhou.vivid2D.events; import com.axis.innovators.box.events.SubscribeEvent; import java.lang.reflect.Method; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; /** * 事件总线 * * @author tzdwindows 7 */ public class EventBus { private static int maxID = 0; private final int busID; // 使用线程安全的集合以支持并发环境 private final Map, List> eventSubscribers = new ConcurrentHashMap<>(); private final Map> targetSubscribers = new ConcurrentHashMap<>(); private volatile boolean shutdown; public EventBus() { this.busID = maxID++; } private static class Subscriber implements Comparable { final Object target; final Method method; final Class eventType; final int priority; // 新增优先级字段 Subscriber(Object target, Method method, Class eventType, int priority) { this.target = target; this.method = method; this.eventType = eventType; this.priority = priority; } @Override public int compareTo(Subscriber other) { // 按优先级降序排序 return Integer.compare(other.priority, this.priority); } } /** * 注册目标对象的事件监听器 * * @param target 目标对象 */ public void register(Object target) { if (targetSubscribers.containsKey(target)) { return; } List subs = new CopyOnWriteArrayList<>(); for (Method method : getAnnotatedMethods(target)) { SubscribeEvent annotation = method.getAnnotation(SubscribeEvent.class); if (annotation == null) { continue; } Class[] paramTypes = method.getParameterTypes(); if (paramTypes.length != 1) { System.err.println("Method " + method.getName() + " has @SubscribeEvent annotation but requires " + paramTypes.length + " parameters. Only one is allowed."); continue; } Class eventType = paramTypes[0]; // 确保事件参数实现了 Event 接口 if (!Event.class.isAssignableFrom(eventType)) { System.err.println("Method " + method.getName() + " has @SubscribeEvent annotation, but its parameter " + eventType.getName() + " does not implement the Event interface."); continue; } Subscriber sub = new Subscriber(target, method, eventType, annotation.priority()); // 使用 computeIfAbsent 简化代码并保证线程安全 List eventSubs = eventSubscribers.computeIfAbsent(eventType, k -> new CopyOnWriteArrayList<>()); eventSubs.add(sub); // 每次添加后都进行排序,以保证优先级顺序 Collections.sort(eventSubs); subs.add(sub); } if (!subs.isEmpty()) { targetSubscribers.put(target, subs); } } /** * 获取目标对象中所有带有 @SubscribeEvent 注解的方法 * * @param target 目标对象 * @return 方法集合 */ private Set getAnnotatedMethods(Object target) { Set methods = new HashSet<>(); Class clazz = target.getClass(); while (clazz != null) { for (Method method : clazz.getDeclaredMethods()) { if (method.isAnnotationPresent(SubscribeEvent.class)) { methods.add(method); } } clazz = clazz.getSuperclass(); } return methods; } /** * 注销目标对象的事件监听器 * * @param target 目标对象 */ public void unregister(Object target) { List subs = targetSubscribers.remove(target); if (subs == null) { return; } for (Subscriber sub : subs) { List eventSubs = eventSubscribers.get(sub.eventType); if (eventSubs != null) { eventSubs.remove(sub); if (eventSubs.isEmpty()) { eventSubscribers.remove(sub.eventType); } } } } /** * 发布事件 * * @param event 事件对象,必须实现 Event 接口 * @return 返回一个 PostResult 对象,其中包含事件是否被取消的状态 */ public PostResult post(Event event) { if (shutdown) { return new PostResult(event.isCancelled(), null); } Class eventType = event.getClass(); List subs = eventSubscribers.get(eventType); if (subs == null || subs.isEmpty()) { return new PostResult(false, null); } for (Subscriber sub : subs) { try { // 无需再创建副本,因为我们使用了 CopyOnWriteArrayList sub.method.setAccessible(true); sub.method.invoke(sub.target, event); // 如果事件被任何一个订阅者取消,则立即停止分发 if (event.isCancelled()) { break; } } catch (Exception e) { handleException(event, sub, e); } } // 默认返回一个空的 Map,您可以根据需要进行修改 Map additionalInfo = new HashMap<>(); return new PostResult(event.isCancelled(), additionalInfo); } /** * 关闭事件总线,停止处理事件 */ public void shutdown() { shutdown = true; eventSubscribers.clear(); targetSubscribers.clear(); } /** * 处理事件处理过程中出现的异常 * * @param event 事件 * @param subscriber 发生异常的订阅者 * @param e 异常 */ private void handleException(Event event, Subscriber subscriber, Exception e) { System.err.println("Exception thrown by subscriber " + subscriber.target.getClass().getName() + "#" + subscriber.method.getName() + " when handling event " + event.getClass().getName()); e.printStackTrace(); } }