`

学习使用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;
	}
}

@Component
public class FinishTaskEventWorkflowHandler extends
		EventListener<FinishTaskEvent> {

	@Override
	public Boolean execute(FinishTaskEvent event) {
		event.getTask().setFinished(true);
		return true;
	}

}

@Component
public class FinishTaskEventHistoryLogger extends
		EventListener<FinishTaskEvent> {

	@Autowired
	HistoryRepository historyRepository;

	@Override
	public 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 {

	@Autowired
	private FinishTaskEventWorkflowHandler finishTaskEventWorkflowHandler;
	@Autowired
	private FinishTaskEventHistoryLogger finishTaskEventHistoryLogger;
	@Autowired
	private HistoryRepository historyRepository;

	@Before
	public void setUp() {
		EventManager.register(finishTaskEventHistoryLogger);
		EventManager.register(finishTaskEventWorkflowHandler);
	}

	@After
	public void tearDown() {
		EventManager.unregister(finishTaskEventHistoryLogger);
		EventManager.unregister(finishTaskEventWorkflowHandler);
	}

	@Test
	public 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);
	}
}
分享到:
评论

相关推荐

    一个用java编写的通讯录

    这个Java编写的通讯录系统,不仅具备基本的数据录入和查询功能,还能够将记录保存为文件,以便于数据的持久化存储和跨设备迁移。 1. **图形用户界面(GUI)设计**: Java提供了丰富的图形用户界面库,如Swing和...

    Java编写线程动画

    - **事件驱动模型**:GUI应用通常基于事件驱动模型,用户操作触发事件,事件处理器响应事件并更新界面。 - **线程动画实现**:在后台线程(非UI线程)上进行计算和更新,然后通过调用Swing或JavaFX的刷新方法在...

    使用Java多线程的同步机制编写应用程序.docx

    这个实验不仅加深了我们对并行/并发、同步/异步的理解,还锻炼了我们使用Java多线程解决实际问题的能力。通过这种方式,我们能够确保在多线程环境下,数据的完整性和一致性,这对于构建复杂的分布式系统或高并发应用...

    如何使用Java编写多线程程序

    ### 如何使用Java编写多线程程序 #### 一、简介 ##### 1.1 什么是线程? 在深入探讨Java中的多线程编程之前,我们需要先了解什么是线程。线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程...

    Java编写的qq聊天室

    【Java编写的qq聊天室】是一个基于Java技术实现的网络通信项目,旨在提供一个简易的在线聊天环境。在这个聊天室中,用户可以进行实时的文字交流,体验类似于QQ的即时通讯功能。下面将详细阐述这个项目涉及到的核心...

    Java2学习指南

    通过学习Thread类和Runnable接口,你可以创建并发执行的任务,了解同步机制如synchronized关键字、wait()、notify()方法,以及线程池的使用,能帮助你在多核处理器环境下充分利用系统资源,编写高效的并发程序。...

    Java编写的多线程下载器源代码

    Swing使用事件驱动模型,当用户进行操作时,会触发相应的事件处理器,使得程序能够响应用户的输入。 下载过程中,进度条的更新是通过计算已下载部分与总大小的比例来实现的。此外,显示下载速度通常需要在每次数据...

    Java事件驱动程序设计相关代码

    - **匿名内部类和Lambda表达式**:在Java 8之后,可以使用Lambda表达式简洁地创建事件监听器,如`button.addActionListener(e -&gt; System.out.println("Button clicked"));`。 - **自定义事件和监听器**:除了内置的...

    java编写的基于jmf的音乐播放器

    本项目“java编写的基于jmf的音乐播放器”利用了JMF的核心功能,实现了音乐播放、滚动歌词显示、进度条控制以及音量调节等功能,提供了良好的用户体验。 1. **JMF介绍** JMF是Sun Microsystems开发的开源库,主要...

    java编写的网络五子棋

    在本项目中,“java编写的网络五子棋”是一个利用Java技术实现的在线五子棋游戏,旨在帮助开发者在学习Java的过程中通过实践来加深理解。 一、Java基础知识 1. 类与对象:Java是面向对象的语言,五子棋游戏的实现将...

    java学习资料初学java教程

    另外,Java并发编程也是重要一环,学习线程的创建、同步和通信,以及如何使用ExecutorService和并发工具类,能帮助你在多核处理器环境下编写高效代码。 在压缩包“源码帝国”中,可能包含了各种示例代码、练习项目...

    利用java编写的井字棋游戏

    在编程领域,实现一个井字棋游戏是初学者学习面向对象编程、事件处理和用户交互的好练习。本项目使用Java语言进行开发,充分展示了Java在游戏编程中的应用。 在Java中,井字棋游戏的实现主要涉及以下几个核心知识点...

    java 编写俄罗斯方块源代码

    通过研究这个Java编写的俄罗斯方块源代码,开发者不仅可以学习到游戏开发的基础,还可以提升自己的编程技能,特别是对于Java GUI编程、事件驱动编程以及多线程应用的理解。同时,这也是一个很好的实践案例,可以让...

    编写多线程的 Java 应用程序

    以下是一个简单的线程同步示例,使用了同步方法: ```java public class Copier { public synchronized void copy() { // 执行复印操作的代码 } } ``` 在这个例子中,`copy()`方法被声明为同步的,这意味着同一...

    操作系统实验 调度问题 java编写

    在实验中,我们可以首先理解各个调度算法的原理,然后用Java编写对应的类和方法。例如,为FCFS算法,我们需要一个队列结构来存储进程,并按其到达时间排序。对于SJF,我们需要考虑进程的执行时间,而优先级调度则...

    Java编写的山寨QQ源代码

    在这个项目中,我们讨论的是一个"Java编写的山寨QQ源代码",它是一个学习和理解Java技术如何应用于即时通讯软件开发的实例。这个项目涉及到的关键知识点包括多线程、图形用户界面(GUI)以及输入/输出(I/O)操作。 ...

    Java 线程的学习和使用

    Java 线程是Java编程中的核心概念,特别是在开发多任务应用时,理解线程的使用至关重要。线程允许程序在同一时间执行...通过学习和实践,开发者可以编写出更加高效、健壮的多线程应用程序,以应对复杂的并发编程挑战。

    java实现的电风扇

    4. **事件驱动编程**:电风扇程序可能使用事件驱动模型,比如当用户点击控制按钮时触发事件,事件处理器负责更新电风扇状态。Java Swing或JavaFX等库提供了丰富的GUI组件和事件处理机制。 5. **线程池**:为了提高...

    Java学习指南上册

    6. **多线程编程**:Java提供了内置的多线程支持,包括Thread类和Runnable接口,理解线程的创建、同步和通信机制,能有效利用多核处理器资源。 7. **反射机制**:反射是Java的一种动态类型特性,允许在运行时检查类...

    Java进阶课堂同步代码.zip

    本资料“Java进阶课堂同步代码.zip”旨在帮助你进一步理解并实践Java的进阶特性,通过实际的代码示例来深化理论学习。 首先,我们关注“java-advanced-master”这个目录,它很可能是这个压缩包的主要内容。在实际的...

Global site tag (gtag.js) - Google Analytics