核心代码:
/**
* 事件基类,保存事件相关数据的值对象。
*/
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编写的通讯录系统,不仅具备基本的数据录入和查询功能,还能够将记录保存为文件,以便于数据的持久化存储和跨设备迁移。 1. **图形用户界面(GUI)设计**: Java提供了丰富的图形用户界面库,如Swing和...
- **事件驱动模型**:GUI应用通常基于事件驱动模型,用户操作触发事件,事件处理器响应事件并更新界面。 - **线程动画实现**:在后台线程(非UI线程)上进行计算和更新,然后通过调用Swing或JavaFX的刷新方法在...
这个实验不仅加深了我们对并行/并发、同步/异步的理解,还锻炼了我们使用Java多线程解决实际问题的能力。通过这种方式,我们能够确保在多线程环境下,数据的完整性和一致性,这对于构建复杂的分布式系统或高并发应用...
### 如何使用Java编写多线程程序 #### 一、简介 ##### 1.1 什么是线程? 在深入探讨Java中的多线程编程之前,我们需要先了解什么是线程。线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程...
【Java编写的qq聊天室】是一个基于Java技术实现的网络通信项目,旨在提供一个简易的在线聊天环境。在这个聊天室中,用户可以进行实时的文字交流,体验类似于QQ的即时通讯功能。下面将详细阐述这个项目涉及到的核心...
通过学习Thread类和Runnable接口,你可以创建并发执行的任务,了解同步机制如synchronized关键字、wait()、notify()方法,以及线程池的使用,能帮助你在多核处理器环境下充分利用系统资源,编写高效的并发程序。...
Swing使用事件驱动模型,当用户进行操作时,会触发相应的事件处理器,使得程序能够响应用户的输入。 下载过程中,进度条的更新是通过计算已下载部分与总大小的比例来实现的。此外,显示下载速度通常需要在每次数据...
- **匿名内部类和Lambda表达式**:在Java 8之后,可以使用Lambda表达式简洁地创建事件监听器,如`button.addActionListener(e -> System.out.println("Button clicked"));`。 - **自定义事件和监听器**:除了内置的...
本项目“java编写的基于jmf的音乐播放器”利用了JMF的核心功能,实现了音乐播放、滚动歌词显示、进度条控制以及音量调节等功能,提供了良好的用户体验。 1. **JMF介绍** JMF是Sun Microsystems开发的开源库,主要...
在本项目中,“java编写的网络五子棋”是一个利用Java技术实现的在线五子棋游戏,旨在帮助开发者在学习Java的过程中通过实践来加深理解。 一、Java基础知识 1. 类与对象:Java是面向对象的语言,五子棋游戏的实现将...
另外,Java并发编程也是重要一环,学习线程的创建、同步和通信,以及如何使用ExecutorService和并发工具类,能帮助你在多核处理器环境下编写高效代码。 在压缩包“源码帝国”中,可能包含了各种示例代码、练习项目...
在编程领域,实现一个井字棋游戏是初学者学习面向对象编程、事件处理和用户交互的好练习。本项目使用Java语言进行开发,充分展示了Java在游戏编程中的应用。 在Java中,井字棋游戏的实现主要涉及以下几个核心知识点...
通过研究这个Java编写的俄罗斯方块源代码,开发者不仅可以学习到游戏开发的基础,还可以提升自己的编程技能,特别是对于Java GUI编程、事件驱动编程以及多线程应用的理解。同时,这也是一个很好的实践案例,可以让...
以下是一个简单的线程同步示例,使用了同步方法: ```java public class Copier { public synchronized void copy() { // 执行复印操作的代码 } } ``` 在这个例子中,`copy()`方法被声明为同步的,这意味着同一...
在实验中,我们可以首先理解各个调度算法的原理,然后用Java编写对应的类和方法。例如,为FCFS算法,我们需要一个队列结构来存储进程,并按其到达时间排序。对于SJF,我们需要考虑进程的执行时间,而优先级调度则...
在这个项目中,我们讨论的是一个"Java编写的山寨QQ源代码",它是一个学习和理解Java技术如何应用于即时通讯软件开发的实例。这个项目涉及到的关键知识点包括多线程、图形用户界面(GUI)以及输入/输出(I/O)操作。 ...
Java 线程是Java编程中的核心概念,特别是在开发多任务应用时,理解线程的使用至关重要。线程允许程序在同一时间执行...通过学习和实践,开发者可以编写出更加高效、健壮的多线程应用程序,以应对复杂的并发编程挑战。
4. **事件驱动编程**:电风扇程序可能使用事件驱动模型,比如当用户点击控制按钮时触发事件,事件处理器负责更新电风扇状态。Java Swing或JavaFX等库提供了丰富的GUI组件和事件处理机制。 5. **线程池**:为了提高...
6. **多线程编程**:Java提供了内置的多线程支持,包括Thread类和Runnable接口,理解线程的创建、同步和通信机制,能有效利用多核处理器资源。 7. **反射机制**:反射是Java的一种动态类型特性,允许在运行时检查类...
本资料“Java进阶课堂同步代码.zip”旨在帮助你进一步理解并实践Java的进阶特性,通过实际的代码示例来深化理论学习。 首先,我们关注“java-advanced-master”这个目录,它很可能是这个压缩包的主要内容。在实际的...