读书人

学习应用java编写简单的同步事件处理器

发布时间: 2012-12-28 10:29:05 作者: rapoo

学习使用java编写简单的同步事件处理器
核心代码:

/** * 事件基类,保存事件相关数据的值对象。 */public abstract class Event {/** 发送事件时间 */protected Date fireTime;public Date getFireTime() {return fireTime;}public void setFireTime(Date fireTime) {this.fireTime = fireTime;}}

/** * 事件监听器,每个监听器绑定特定事件,该事件由泛型指定。 * * @param <T> *            特定事件 */public abstract class EventListener<T extends Event> {/** 该监听器是否触发一次即注销,默认为否 */protected boolean runOnce = false;/** * 处理事件,由继承类实现。 *  * @param event *            事件类型,则事件监听器的泛型 * @return 返回<code>true</code>则事件继续触发下一个事件监听器,否则终止事件 */public abstract Boolean execute(T event);public boolean isRunOnce() {return runOnce;}public EventListener<T> runOnce(boolean runOnce) {this.runOnce = runOnce;return this;}/** * 通过反射,继承类可以获取泛型事件参数的类型。 *  * @return 泛型事件参数类型 */@SuppressWarnings("unchecked")public Class<T> getEventClass() {return GenericUtils.getSuperClassGenericType(this.getClass());}/** * 注册事件监听器的快捷方式。 */public void register() {EventManager.register(this);}/** * 注销事件监听器的快捷方式。 */public void unre1gister() {EventManager.unregister(this);}}

/** * 事件管理器,提供静态方法用于注册、注销和发送事件。 */public class EventManager {private static Logger logger = LoggerFactory.getLogger(EventManager.class);/** 事件类型 - 事件监听器实体映射 */        /** 使用guava包的多值不重复map保存 */private static Multimap<Class<? extends Event>, EventListener<? extends Event>> eventHook = Multimaps.synchronizedMultimap(LinkedHashMultimap.<Class<? extends Event>, EventListener<? extends Event>> create());/** * 注册事件。 *  * @param listener *            事件监听器 */public static void register(EventListener<? extends Event> listener) {Class<? extends Event> eventClass = listener.getEventClass();eventHook.put(eventClass, listener);if (logger.isDebugEnabled()) {logger.debug("事件监听器 '" + listener.getClass().getSimpleName()+ "' 注册事件 '" + eventClass.getSimpleName() + "'");}}/** * 注销事件。 *  * @param listener *            事件监听器 */public static void unregister(EventListener<? extends Event> listener) {Class<? extends Event> eventClass = listener.getEventClass();eventHook.remove(eventClass, listener);if (logger.isDebugEnabled()) {logger.debug("事件监听器 '" + listener.getClass().getSimpleName()+ "' 注销事件 '" + eventClass.getSimpleName() + "'");}}/** * 发送特定事件。 *  * @param event *            事件实体 * @throws Exception *             反射异常 */public static void fire(Event event) throws Exception {event.setFireTime(new Date());// 记录发送事件时间Class<? extends Event> eventClass = event.getClass();Collection<EventListener<? extends Event>> listeners = eventHook.get(eventClass);if (logger.isDebugEnabled()) {logger.debug("事件 '" + eventClass.getSimpleName() + "' 监听器数目: "+ listeners.size());}for (Iterator<EventListener<? extends Event>> iterator = listeners.iterator(); iterator.hasNext();) {// 遍历所有注册该事件的事件监听器EventListener<? extends Event> listener = iterator.next();// 因为每个事件监听器的execute方法参数由泛型指定// 所以要通过反射,将事件实体注入并执行事件监听器的execute方法Method execute = listener.getClass().getMethod("execute",eventClass);boolean stop = !(Boolean) execute.invoke(listener, event);if (logger.isDebugEnabled()) {logger.debug("事件 '" + eventClass.getSimpleName()+ "' 触发事件监听器 '" + listener.getClass().getSimpleName()+ "'");}if (listener.isRunOnce()) {iterator.remove();if (logger.isDebugEnabled()) {logger.debug("移除事件监听器 '"+ listener.getClass().getSimpleName() + "'");}}if (stop) {if (logger.isDebugEnabled()) {logger.debug("事件 '" + eventClass.getSimpleName()+ "' 被事件监听器 '"+ listener.getClass().getSimpleName() + "' 终止");}break;}}}}


Demo主要代码:
public class FinishTaskEvent extends TaskEvent {public FinishTaskEvent(Task task) {this.task = task;}}

@Componentpublic class FinishTaskEventWorkflowHandler extendsEventListener<FinishTaskEvent> {@Overridepublic Boolean execute(FinishTaskEvent event) {event.getTask().setFinished(true);return true;}}

@Componentpublic class FinishTaskEventHistoryLogger extendsEventListener<FinishTaskEvent> {@AutowiredHistoryRepository historyRepository;@Overridepublic Boolean execute(FinishTaskEvent event) {String taskName = event.getTask().getName();String assignee = event.getTask().getAssignee();historyRepository.addHistory(("用户 '" + assignee + "' 完成任务: " + taskName));return true;}}


单元测试:
@ContextConfiguration("classpath:/applicationContext.xml")public class EventTest extends AbstractJUnit4SpringContextTests {@Autowiredprivate FinishTaskEventWorkflowHandler finishTaskEventWorkflowHandler;@Autowiredprivate FinishTaskEventHistoryLogger finishTaskEventHistoryLogger;@Autowiredprivate HistoryRepository historyRepository;@Beforepublic void setUp() {EventManager.register(finishTaskEventHistoryLogger);EventManager.register(finishTaskEventWorkflowHandler);}@Afterpublic void tearDown() {EventManager.unregister(finishTaskEventHistoryLogger);EventManager.unregister(finishTaskEventWorkflowHandler);}@Testpublic void testFinishTaskEvent() throws Exception {Task task1 = new Task("任务1", "用户A");EventManager.fire(new FinishTaskEvent(task1));Assert.assertTrue(task1.isFinished());Task task2 = new Task("任务2", "用户B");EventManager.fire(new FinishTaskEvent(task2));Assert.assertTrue(task2.isFinished());String[] actuals = historyRepository.getHistories().toArray(new String[2]);String[] expecteds = new String[] { "用户 '用户A' 完成任务: 任务1","用户 '用户B' 完成任务: 任务2" };Assert.assertArrayEquals(expecteds, actuals);}}

读书人网 >编程

热点推荐