事件驱动模型的简单Java实现

事件驱动模型的原理不再赘述,Swing是不错的实现。别人也有不错的博文来说明原理。

本文的目的是提供一种简单的,可供参考的简短代码,用来帮助理解该模型。

Project Navigator

事件驱动模型的简单Java实现

Event

事件通用接口:

  1. package org.joshua.event.events;
  2. public interface Event {
  3. }

Click事件:

  1. package org.joshua.event.events;
  2. public class ClickEvent implements Event {
  3. }

Double click事件:

  1. package org.joshua.event.events;
  2. public class DblClickEvent implements Event {
  3. }

Listener

事件监听器通用接口:

  1. package org.joshua.event.listener;
  2. import org.joshua.event.events.Event;
  3. public interface EventListener<T extends Event> {
  4. public void handleEvent(T event);
  5. }

Click事件监听器:

  1. package org.joshua.event.listener;
  2. import org.joshua.event.events.ClickEvent;
  3. public interface ClickEventHandler extends EventListener<ClickEvent> {
  4. }

Double Click事件监听器:

  1. package org.joshua.event.listener;
  2. import org.joshua.event.events.DblClickEvent;
  3. public interface DblClickEventHandler extends EventListener<DblClickEvent> {
  4. }

Event Source

事件源通用接口:

  1. package org.joshua.event.source;
  2. import org.joshua.event.events.Event;
  3. import org.joshua.event.listener.EventListener;
  4. public interface EventSource {
  5. void addEventListener(EventListener<? extends Event> listener);
  6. void removeEventListener(EventListener<? extends Event> listener);
  7. void notifyListeners(Event event);
  8. }

模拟的按钮控件:

  1. package org.joshua.event.source;
  2. import java.util.LinkedList;
  3. import java.util.List;
  4. import org.joshua.event.events.Event;
  5. import org.joshua.event.listener.EventListener;
  6. public class Button implements EventSource {
  7. protected List<EventListener<? extends Event>> listeners = new LinkedList<EventListener<? extends Event>>();
  8. @Override
  9. public void addEventListener(EventListener<? extends Event> listener) {
  10. listeners.add(listener);
  11. }
  12. @Override
  13. public void removeEventListener(EventListener<? extends Event> listener) {
  14. listeners.remove(listener);
  15. }
  16. @Override
  17. public void notifyListeners(Event event) {
  18. for (EventListener listener : listeners) {
  19. try {
  20. listener.handleEvent(event);
  21. } catch (ClassCastException e) {
  22. }
  23. }
  24. }
  25. }

Client

  1. package org.joshua.event;
  2. import org.joshua.event.events.ClickEvent;
  3. import org.joshua.event.events.DblClickEvent;
  4. import org.joshua.event.events.Event;
  5. import org.joshua.event.listener.ClickEventHandler;
  6. import org.joshua.event.listener.DblClickEventHandler;
  7. import org.joshua.event.source.Button;
  8. import org.junit.Before;
  9. import org.junit.Test;
  10. public class Client {
  11. private Event currentEvent;
  12. private Button button;
  13. @Before
  14. public void initComponent() {
  15. button = new Button();
  16. button.addEventListener(new ClickEventHandler() {
  17. @Override
  18. public void handleEvent(ClickEvent event) {
  19. System.out.println("Button was clicked!");
  20. }
  21. });
  22. button.addEventListener(new DblClickEventHandler() {
  23. @Override
  24. public void handleEvent(DblClickEvent event) {
  25. System.out.println("Button was double clicked!");
  26. }
  27. });
  28. }
  29. @Test
  30. public void testCommonEvents() {
  31. currentEvent = new ClickEvent();
  32. button.notifyListeners(currentEvent);
  33. currentEvent = new DblClickEvent();
  34. button.notifyListeners(currentEvent);
  35. }
  36. }

Button类中的notifyListener方法实现起来虽方便,利用了一把异常机制,但着实不推荐大家在项目中这样做。且不说性能问题,Listener的handleEvent方法里所有抛出的ClassCastException都需要重新包装。当然,我们可以使用annotation、限定类名等方式相对优雅地解决event和对应listener的mapping问题。

多线程事件处理机制

思路是用队列暂存事件,然后若干个事件分发器将事件分发给指定数量的事件处理线程处理。

  1. package com.joshua.test.event;
  2. import java.util.concurrent.BlockingQueue;
  3. import java.util.concurrent.ExecutorService;
  4. import java.util.concurrent.Executors;
  5. import java.util.concurrent.LinkedBlockingQueue;
  6. import com.joshua.test.event.event.Event;
  7. import com.joshua.test.event.event.EventType;
  8. import com.joshua.test.event.handler.CreateEventHandler;
  9. public class EventManager {
  10. private static final int EVENT_QUEUE_LENGTH = 1000;
  11. private static final int DISPATCHER_NUM = 2;
  12. private static final int EVENT_HANDLER_NUM = 10;
  13. public BlockingQueue<Event> eventQueue = new LinkedBlockingQueue<Event>(EVENT_QUEUE_LENGTH);
  14. private ExecutorService eventHandlerPool;
  15. protected EventDispatcher createDispatcher() {
  16. EventDispatcher dispatcher = new EventDispatcher(this.eventQueue, this.eventHandlerPool);
  17. dispatcher.register(EventType.CREATE, CreateEventHandler.class);
  18. return dispatcher;
  19. }
  20. public void init() {
  21. eventHandlerPool = Executors.newFixedThreadPool(EVENT_HANDLER_NUM);
  22. }
  23. public void start() {
  24. for (int i = 0; i < DISPATCHER_NUM; i++) {
  25. createDispatcher().start();
  26. }
  27. }
  28. public void notify(Event event) {
  29. try {
  30. eventQueue.put(event);
  31. } catch (InterruptedException e) {
  32. }
  33. }
  34. }
  1. package com.joshua.test.event;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. import java.util.concurrent.BlockingQueue;
  5. import java.util.concurrent.ExecutorService;
  6. import com.joshua.test.event.event.Event;
  7. import com.joshua.test.event.event.EventType;
  8. import com.joshua.test.event.handler.EventHandler;
  9. @SuppressWarnings("rawtypes")
  10. public class EventDispatcher {
  11. private final BlockingQueue<Event> eventQueue;
  12. private final ExecutorService eventHandlerPool;
  13. protected final Map<EventType, Class<? extends EventHandler>> eventDispatchers = new HashMap<EventType, Class<? extends EventHandler>>();
  14. private Thread eventHandlingThread;
  15. private volatile boolean stopped = false;
  16. public EventDispatcher(BlockingQueue<Event> eventQueue, ExecutorService eventHandlerPool) {
  17. this.eventQueue = eventQueue;
  18. this.eventHandlerPool = eventHandlerPool;
  19. System.out.println("Event dispatcher starting...");
  20. }
  21. Runnable createThread() {
  22. return new Runnable() {
  23. @Override
  24. public void run() {
  25. while (!stopped && !Thread.currentThread().isInterrupted()) {
  26. Event event;
  27. try {
  28. event = eventQueue.take();
  29. } catch (InterruptedException ie) {
  30. if (!stopped) {
  31. System.out.println("Dispatcher thread interrupted");
  32. ie.printStackTrace();
  33. }
  34. return;
  35. }
  36. if (event != null) {
  37. dispatch(event);
  38. }
  39. }
  40. }
  41. };
  42. }
  43. @SuppressWarnings("unchecked")
  44. protected void dispatch(Event event) {
  45. EventType type = event.getType();
  46. try {
  47. Class<? extends EventHandler> handlerClazz = eventDispatchers
  48. .get(type);
  49. if (handlerClazz != null) {
  50. EventHandler handler = handlerClazz.newInstance();
  51. handler.setEvent(event);
  52. eventHandlerPool.submit(handler);
  53. } else {
  54. throw new Exception("No handler for registered for " + type);
  55. }
  56. } catch (Throwable t) {
  57. System.err.println("Error in dispatcher thread");
  58. t.printStackTrace();
  59. System.exit(-1);
  60. }
  61. }
  62. public void register(EventType eventType,
  63. Class<? extends EventHandler> handler) {
  64. Class<? extends EventHandler> registeredHandler = eventDispatchers
  65. .get(eventType);
  66. System.out.println("Registering " + eventType + " for "
  67. + handler);
  68. if (registeredHandler == null) {
  69. eventDispatchers.put(eventType, handler);
  70. }
  71. }
  72. public void start() {
  73. eventHandlingThread = new Thread(createThread());
  74. eventHandlingThread.setName("AsyncDispatcher event handler");
  75. eventHandlingThread.start();
  76. System.out.println("Event dispatcher started!");
  77. }
  78. public void stop() {
  79. stopped = true;
  80. if (eventHandlingThread != null) {
  81. eventHandlingThread.interrupt();
  82. try {
  83. eventHandlingThread.join();
  84. } catch (InterruptedException ie) {
  85. System.out.println("Interrupted Exception while stopping");
  86. ie.printStackTrace();
  87. }
  88. }
  89. }
  90. }
上一篇:JVM进程占用CPU过高问题排查


下一篇:SQL Server 2008中SQL之WaitFor