| 内置监听器            |                              |                  |
|------------------|------------------------------|------------------|
| SimpleListener   | 简单监听器                        | Listener 的空实现    |
| PipelineListener | 管道监听器                        | Listener 的链式组织实现 |
| EventListener    | 事件监听器，根据消息事件路由（message::event） | 相当于消息的路由器        |
| PathListener     | 路径监听器，根据连接地址路由（session::path）  | 相当于路径（频道）的路由器    |


### 1、SimpleListener（简单监听器）

就是一个空实现，用时只需要重写需要的方法。下面的都是链式写法，有些小伙伴可能不喜欢。


### 2、 EventListener（事件监听器，根据消息事件路由）

它相当于是事件（event）的路由器。可以直接在上面配置事件监听，也可以通过它做分发处理。

```java
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（管道监听器）

```java
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 集群模式下可能用处不大。

```java
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 框架，是非常容易的事情。以下可为参考：

```java
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);
        }
    }
}
```
