监听器应用示例
内置监听器 | ||
---|---|---|
SimpleListener | 简单监听器 | Listener 的空实现 |
PipelineListener | 管道监听器 | Listener 的链式组织实现 |
EventListener | 事件监听器,根据消息事件路由(message::event) | 相当于消息的路由器 |
PathListener | 路径监听器,根据连接地址路由(session::path) | 相当于路径(频道)的路由器 |
1、SimpleListener(简单监听器)
就是一个空实现,用时只需要重写需要的方法。下面的都是链式写法,有些小伙伴可能不喜欢。
2、 EventListener(事件监听器,根据消息事件路由)
它相当于是事件(event)的路由器。可以直接在上面配置事件监听,也可以通过它做分发处理。
public class Demo {
public static void main(String[] args) throws Throwable {
//::启动服务端
SocketD.createServer("sd:tcp")
.config(c -> c.port(8602))
.listen(new EventListener().doOnMessage((s,m)->{
System.out.println(m);
s.send("/demo", new StringEntity("Me too!"));
}).doOn("/order", (s,m)->{ //根据消息事件路由
System.out.println(m); //在 onMessage 时已打印一次,这算第二次打印
}).doOn("/user", (s,m)->{ //根据消息事件路由
System.out.println(m); //在 onMessage 时已打印一次,这算第二次打印
}))
.start();
Thread.sleep(1000); //等会儿,确保服务端启动完成
//::打开客户端会话
ClientSession clientSession = SocketD.createClient("sd:tcp://127.0.0.1:8602/?u=a&p=2")
.listen(new EventListener().doOnMessage((s, m) -> {
System.out.println(m);
}).doOn("/demo", (s, m) -> { //根据消息事件路由
System.out.println(m);
}))
.open();
clientSession.send("/order", new StringEntity("Hi"));
clientSession.send("/user", new StringEntity("Hi"));
}
}
3、 PipelineListener(管道监听器)
public class Demo {
public static void main(String[] args) throws Throwable {
//::启动服务端
SocketD.createServer("sd:udp")
.config(c -> c.port(8602))
.listen(new PipelineListener().next(new EventListener().doOnMessage((s, m) -> {
//这里可以做拦截
System.out.println("拦截打印::" + m);
})).next(new EventListener().doOnMessage((s, m) -> {
//这里可以做业务处理
System.out.println(m);
})))
.start();
Thread.sleep(1000); //等会儿,确保服务端启动完成
//::打开客户端会话
ClientSession clientSession = SocketD.createClient("sd:udp://127.0.0.1:8602/hello?u=a&p=2")
.open();
clientSession.send("/demo", new StringEntity("Hi"));
}
}
4、 PathListener(路径监听器,根据连接地址路由)
它相当于是连接地址(path)的路由器,可以起到频道隔离的效果。不过,在 Broker 集群模式下可能用处不大。
public class Demo04_Router {
public static void main(String[] args) throws Throwable {
//::启动服务端
SocketD.createServer("sd:tcp")
.config(c -> c.port(8602))
.listen(new PathListener()
.doOf("/", new EventListener().doOnMessage((s, m) -> {
//用户频道
System.out.println("user::" + m);
}))
.doOf("/admin", new EventListener()
.doOnOpen(s -> {
//管理员频道
if ("admin".equals(s.param("u")) == false) {
s.close();
}
}).doOnMessage((s, m) -> {
System.out.println("admin::" + m);
})
)
)
.start();
Thread.sleep(1000); //等会儿,确保服务端启动完成
//::打开客户端会话
//用户频道(链接地址的 path ,算为频道)
ClientSession clientSession1 = SocketD.createClient("sd:tcp://127.0.0.1:8602/?u=a&p=2").open();
clientSession1.send("/demo", new StringEntity("Hi"));
//管理员频道(链接地址的 path ,算为频道)
ClientSession clientSession2 = SocketD.createClient("sd:tcp://127.0.0.1:8602/admin?u=a&p=2").open();
clientSession2.send("/demo", new StringEntity("Hi"));
}
}
5、 定制应用
这个定制是一个真实的案例:Solon 项目通过 Socket.D 监听器,将消息转换成 Context 并交给 Handler 接口处理,从而实现 Mvc 效果。这也是 Solon Rpc 的实现方案之一。
使用 Socket.D 开发 Rpc 框架,是非常容易的事情。以下可为参考:
public class ToHandlerListener extends SimpleListener {
private static final Logger log = LoggerFactory.getLogger(ToHandlerListener.class);
@Override
public void onMessage(Session session, Message message) throws IOException {
if (Utils.isEmpty(message.event())) {
log.warn("This message is missing route, sid={}", message.sid());
return;
}
try {
SocketdContext ctx = new SocketdContext(session, message);
Solon.app().tryHandle(ctx);
if (ctx.getHandled() || ctx.status() != 404) {
ctx.commit();
}
} catch (Throwable e) {
//context 初始化时,可能会出错
//
log.warn(e.getMessage(), e);
}
}
}