实践事件派发器模式

在项目开发中,会遇到如下情形:我们自己的服务订阅、接收来自消息队列或者客户端的事件和请求,基于不同的事件采取对应的行动,这种情况下适合应用派发器模式。

XXXEventDispatcher类

核心类,维护事件类型(EventType)到处理器(handler)的映射(存放在ConcurrentHashMap中);这个类在启动时,会通过XXXEventHandlerInitializer初始化这个map数据结构;在启动时,需要订阅或监听来自消息队列的事件;当对应的事件到达时,该类的dispatch方法会负责将事件分发到具体的处理器方法中进行处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package org.java.learn.java8.dispatcher;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
/**
* Created by IntelliJ IDEA.
* User: duqi
* Date: 2016/11/3
* Time: 21:53
*/
@Component
public class XXXEventDispatcher implements AutoCloseable {
@Resource
private XXXEventHandlerInitializer initializer;

private Map<XXXEventType, XXXEventHandler> handlers = new ConcurrentHashMap<>();

@PostConstruct
public void init() {
//建立绑定关系;
initializer.init();
//监听事件并派发
dispatch("testMsg");
}

/**
* 将XXX事件注册到派发器
*
* @param xxxEventType
* @param xxxEventHandler
*/
public void bind(XXXEventType xxxEventType, XXXEventHandler xxxEventHandler) {
this.handlers.put(xxxEventType, ((eventType, context) -> {
try {
xxxEventHandler.handle(eventType, context);
} catch (Exception e) {
//记录错误日志
e.printStackTrace();
}
//打印处理器执行日志
}));
}

/**
* 进行事件派发
* @param eventMsg
*/
private void dispatch(String eventMsg) {
//(1) 从eventMsg中获取eventType;
//(2) 根据eventMsg构造eventContext;
//(3) 执行具体的处理器方法
}

public void close() throws Exception {
//释放资源
}
}

XXXEventHandlerInitializer类

这个类包括具体的业务处理方法,在系统初始化的时候,会将这些业务处理方法的方法引用注册到派发器中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package org.java.learn.java8.dispatcher;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* Created by IntelliJ IDEA.
* User: duqi
* Date: 2016/11/3
* Time: 21:56
*/
@Component
public class XXXEventHandlerInitializer {
@Resource
private XXXEventDispatcher dispatcher;

public void init() {
dispatcher.bind(XXXEventType.event1, this::handleProcess1);
dispatcher.bind(XXXEventType.event2, this::handleProcess2);
dispatcher.bind(XXXEventType.event3, this::handleProcess3);
}

private void handleProcess1(XXXEventType eventType, XXXEventContext context) {
//事件1的处理逻辑
}

private void handleProcess2(XXXEventType eventType, XXXEventContext context) {
//事件2的处理逻辑
}

private void handleProcess3(XXXEventType eventType, XXXEventContext context) {
//事件3的处理逻辑
}
}

XXXEventHandler:函数式接口

函数式接口是Java 8 中实现Lambda函数式编程的基础工具,思想就是要讲函数作为参数传递。如下图所示,这些方法引用都是该函数式接口的实现。
函数式接口的实现
代码如下:

1
2
3
4
5
6
7
8
9
10
11
package org.java.learn.java8.dispatcher;
/**
* Created by IntelliJ IDEA.
* User: duqi
* Date: 2016/11/3
* Time: 22:03
*/
@FunctionalInterface
public interface XXXEventHandler {
void handle(XXXEventType eventType, XXXEventContext context);
}

XXXEventContext类

这个类用于存储入参和返回值,具体情况可以灵活处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package org.java.learn.java8.dispatcher;
/**
* Created by IntelliJ IDEA.
* User: duqi
* Date: 2016/11/3
* Time: 22:04
*/
public class XXXEventContext {
private int param1;
private int param2;

@Override
public String toString() {
return "XXXEventContext{" +
"param1=" + param1 +
", param2=" + param2 +
'}';
}
}

XXXEventType枚举

这个类显然用于存储事件类型

1
2
3
4
5
6
7
8
9
10
11
12
package org.java.learn.java8.dispatcher;
/**
* Created by IntelliJ IDEA.
* User: duqi
* Date: 2016/11/3
* Time: 22:03
*/
public enum XXXEventType {
event1,
event2,
event3
}

总结

在企业级开发中,有很多典型的应用场景和模式,事件派发器只是其中的一种,希望你也能够根据自己的实际情况加以应用。本文中提到的代码,参见我的github:LearnJava