昨天想写个Event Driven模式,看了不少资料也成功写出了一个实现,先简单说下,以后细聊
Event Driven 事件驱动模式
- Event Bus 模式 传递消息的,复杂的是在主机间传递
- Event Driven 模式 处理消息的,通常与 Event Bus 工作在一起,复杂的是实现消息通信模式
- Reactor 模式 同 Event Driven 模式,只是关注 IO 事件
消息通信模式
- 发布/订阅 模式 消息被发布到一个address/topic,也就是说派发消息到所有注册在这个address/topic 的处理器去处理
- 点对点 模式 同上,不过消息只被派发到一个处理器上
- 请求/响应 模式 同点对点,不过处理器还能回一个消息给消息生产者,生产者能接受到这个消息
更多资料
- 掘金 - 一文理解Netty模型架构
- 大凡的博客 - 《Scalable IO in Java》译文
- Vert.x逐陆记 - 1.7.EventBus初探
- Vert.x Core Manual - The Event Bus
代码
测试
代码命名和设计真的参考了Vert.X很多,先给一段测试结果
// 接口的静态工厂方法,总是返回同一个单例实现
EventBus eventBus = EventBus.bus();
AtomicInteger id = new AtomicInteger(1);
// 调用 eventbus api 来常见消费者,或者叫处理器
eventBus.<String>consumer("comment.post", msg -> {
System.out.println("消费者-1: 【消息已持久化到数据库】" + msg);
});
eventBus.<String>consumer("comment.post", msg -> {
System.out.println("消费者-2: 【你有一条新回复】" + msg.data());
});
// 通过返回的 MessageConsumer 引用,方便注销这个消费者
var c3 = eventBus.<Integer>consumer("comment.notify", msg -> {
System.out.println("消费者-3: 【点赞通知】已获得 " + msg.data() + " 个赞");
});
// 构建两个消息/事件生产者
MessageProducer<String> producer1 = eventBus.producer("comment.post");
MessageProducer<Integer> producer2 = eventBus.producer("comment.notify");
// 模拟一个事件/消息流
IntStream.range(1, 501).forEach( i -> {
producer1.write("已三连,谢谢UP主 #" + id.getAndIncrement());
producer2.write(i);
});
// 通过 eventbus 直接发消息
eventBus.<String>send("comment.post", "最后一层了!");
// 注销消费者/处理器
// c3.unregister();
接口和类设计
Acceptor.java
package com.onemsg.plan.eda;
/**
* Acceptor 事件/消息 接收者
*/
public interface Acceptor {
/**
* 开启事件循环
*/
void startEventLoop();
/**
* 接受一个消息
*/
void accept(Message<Object> event);
/**
* 关闭
*/
void close();
}
Dispatcher.java
package com.onemsg.plan.eda;
import java.util.Set;
/**
* 事件/消息 调度者
*/
public interface Dispatcher {
/**
* 派发一个事件给对应的处理器
* @param event 事件
*/
void dispatch(Message<Object> event);
/**
* 所有的消息地址/主题
* @return 消息地址集合
*/
Set<String> addresses();
/**
* 返回在指定消息地址注册的处理器集合
* @param address
* @return 处理器集合
*/
Set<MessageConsumer<Object>> consumeres(String address);
/**
* 注册新的事件消费者
* @param consumer
* @return true/false 表示成功或失败
*/
boolean addRegistration(MessageConsumer<Object> consumer);
/**
* 注销一个事件消费者
* @param <T>
* @param consumer
* @return true/false 是否注销成功
*/
<T> boolean removeRegistration(MessageConsumer<T> consumer);
void close();
}
EventBus.java
package com.onemsg.plan.eda;
import java.util.Map;
import com.onemsg.plan.eda.impl.EventBusImpl;
/**
* <p>事件总线</p>
* <p>一般作为主要的用户使用接口</p>
*/
public interface EventBus {
/**
* 向指定地址添加新的事件处理器,返回一个新的事件消费者
* @param <T>
* @param address
* @param handler
* @return 事件消费者
*/
<T> MessageConsumer<T> consumer(String address, Handler<Message<T>> handler);
/**
* 返回给定地址的新的时间消费者
* @param <T> 数据类型
* @param address
* @return 事件消费者
*/
<T> MessageConsumer<T> consumer(String address);
/**
* 向给定地址发送事件,包含数据
* @param <T> 数据类型
* @param address
* @param data 要发送的数据
*/
<T> void send(String address, T data);
/**
* 像给定地址发送事件,包含数据和消息头
* @param <T> 数据类型
* @param address
* @param data 要发送的数据
* @param headers 消息头
*/
<T> void send(String address, T data, Map<String, String> headers);
/**
* 发送一个事件,地址和数据不能为空,否则抛出异常
* @param <T> 数据类型
* @param event 事件
*/
<T> void send(Message<T> event) throws NullPointerException;
/**
* 返回给定地址的消息成产值
* @param <T>
* @param address
* @return
*/
<T> MessageProducer<T> producer(String address);
void close();
/**
* 返回一个单例 EventBus
*/
static EventBus bus(){
return EventBusImpl.instance();
}
}
Handler.java
package com.onemsg.plan.eda;
/**
* 事件/消息 处理器
* <p>这是一个函数式接口</p>
*/
@FunctionalInterface
public interface Handler<E> {
void handle(E event);
}
Message.java
package com.onemsg.plan.eda;
import java.util.Map;
/**
* 事件/消息
* @param <T> 数据类型
*/
public interface Message<T> {
/**
* @return 地址
*/
String address();
/**
* @return 消息头
*/
Map<String,String> headers(