目录
核心类
各个击破
- IoService
- IoFilter
- IoHandler
总结
# 加入战队
微信公众号
Mina 异步 IO 使用的 Java 底层 JNI 框架, Mina 提供服务端和客户端, 将我们的业务解耦开发. 真正做到高内聚低耦合的思想
核心类
IoService :Mina 中将服务端和客户端都看成是服务, 这里提供统一接口 IoService, 这个接口的作用就是用来处理套接字机制. 也正是 IoService 来监听消息返回消息这些步骤,
可以说 IoService 就是我们 Mina 中核心
IoProcessor: 这个接口在另一个线程上, 负责检查是否有数据在通道上读写, 也就是说它也拥有自己的 Selector, 这是与我们使用 JAVA NIO 编码时的一个不同之处, 通常在 JAVA NIO 编码中, 我们都是使用一个 Selector, 也就是不区分 IoService 与 IoProcessor 两个功能接口. 另外, IoProcessor 负责调用注册在 IoService 上的过滤器, 并在过滤器链之后调用 IoHandler
IoFilter : 定义了一些拦截器 , 和我们 web 中拦截器一样, 用来横向拦截处理一些全局的操作 (日志处理, 编码处理). 其中我们必须注意的是加解密消息.
作为一个好的框架肯定是有默认的拦截器的 (TextLineCodecFactory ). 默认拦截器可以叫消息强制转换为 String 类型. 毕竟 String 最通用
IoHandler : 这个是我们处理消息的逻辑, 前面的拦截器只是在接受是进行一些验证, 翻译的功能. 拿到数据之后我们需要做的事情就是在 IoHandler 中
各个击破
IoService
首先我们已服务端 NioSocketAcceptor 为列, 看看我们的服务类之间的结构依赖关系
IoService 是服务的鼻祖, 无论在我们看来的服务端还是客户端都得继承它 (间接继承). 在 IoService 中我们会定义我们消息的处理过滤器 (上文的拦截器), 消息处理的业务类
在上文简介中我们知道, 这一步其实是 IoProcessor 来完成, 那么 IoProcessor 在什么出现呢. 比如 Mina 框架中用来创建服务端类 NioSocketAcceptor. 他直接继承了 AbstractPollingIoAcceptor. 而 AbstractPollingIoAcceptor 类中根据参数创建了我们需要的 IoProcessor. 从而我们有了 IoProcessor 就可以执行消息间的通信了.
所以过滤器, 处理器实在我们服务启动之前配置好的. 一旦启动成功就无法再修改了. 我们服务端 NioSocketAcceptor 通过 bind 方法就可以绑定到指定端口上. 我们这里的绑
定实现了多态绑定. 我们可以绑定多个服务.
- /**
- * {@inheritDoc}
- */
- @Override
- public final void bind(Iterable<? extends SocketAddress> localAddresses) throws IOException {
- if (isDisposing()) {
- throw new IllegalStateException("The Accpetor disposed is being disposed.");
- }
- if (localAddresses == null) {
- throw new IllegalArgumentException("localAddresses");
- }
- List<SocketAddress> localAddressesCopy = new ArrayList<>();
- for (SocketAddress a : localAddresses) {
- checkAddressType(a);
- localAddressesCopy.add(a);
- }
- if (localAddressesCopy.isEmpty()) {
- throw new IllegalArgumentException("localAddresses is empty.");
- }
- boolean activate = false;
- synchronized (bindLock) {
- synchronized (boundAddresses) {
- if (boundAddresses.isEmpty()) {
- activate = true;
- }
- }
- if (getHandler() == null) {
- throw new IllegalStateException("handler is not set.");
- }
- try {
- Set<SocketAddress> addresses = bindInternal(localAddressesCopy);
- synchronized (boundAddresses) {
- boundAddresses.addAll(addresses);
- }
- } catch (IOException | RuntimeException e) {
- throw e;
- } catch (Exception e) {
- throw new RuntimeIoException("Failed to bind to:" + getLocalAddresses(), e);
- }
- }
- if (activate) {
- getListeners().fireServiceActivated();
- }
- }
在上面我们可以看到 bind 最后是去激活对应的监听器. 我们一个 IoServer 处理一个线程中的消息. 我们监听器就是监听线程内的消息. 每一次的绑定都会有不同的监听器, ioSession 去专门处理消息之间的通信. 我们可以通过 IoSession 设置一些请求数据完成数据的权限验证.
在服务创建的时候我们正常需要设置 IoSession 的一些配置. 通过 getSessionConfig 方法获取 IoSessionConfig. 里面设置参数常用如下:
setReadBufferSize : 设置读取数据的缓冲区大小
setMinReadBufferSize: 设置缓冲区最大值
setMaxReadBufferSize: 设置缓冲区最小值
setThroughputCalculationInterval: 设置通道计算时间 默认 3s
setIdleTime(IdleStatus status, int idleTime): status 设置是一方还是双方 , idLetime 是超过多久就会进入空闲状态
- IoAcceptor acceptor=new NioSocketAcceptor();
- acceptor.getSessionConfig().setReadBufferSize(2048);
- acceptor.getSessionConfig.setIdleTime(IdleStatus.BOTH_IDLE,10);
- IoFilter
在 IoService 中有获取 filter 链的一个方法 DefaultIoFilterChainBuilder getFilterChain() , 我们需要做的就是定义过滤器, 然后通过该方法获取过滤链加入到请求链上.
我们自定义过滤器也很简单, 只需要继承 IoFilterAdapter 这个类就好了.
- acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(
- Charset.forName("UTF-8"),LineDelimeter.Windows.getValue(),LineDelimiter. Windows.getValue()))
- );
TextLineCodecFactory 这个类是 Mina 提供的编解码工厂, 这个工厂的特性是以换行符'\r\n'为结束通信的标志. 也就是说如果我们传递消息没有换行符, 另外一段会继续
接受消息知道接受到'\r\n'才会接受, 并把接受到的消息通过编解码器转到 IoHandler 层供业务层处理.(这里博主被坑在这里了)
IoHandler
到了这一步, 我们的通信基本就已经完成了. 剩下的事情已经和 Mina 基本没多大关联了. 我们将在这里处理业务逻辑, 使用到的就是 Handler 提供的接收消息和发送消息两个功能.
这里我们需要注意的是 Handler 提供 messageReceived 和 messageSent 并不是字面意思. 前者就是消息的接受, 但是后者并不是消息的发送. 我们常用的发送消息是 session.write 方法.
总结
今天我们了解了 Mina 工作的流程, 主要就是 IoFilter 和 IoHandler 实现消息的通信 . 千里之行始于足下, 一点一点的进步. 下面贴出一份总结的图谱帮助我们理解 Mina 流程
加入战队
# 加入战队
微信公众号
来源: https://www.cnblogs.com/zhangxinhua/p/11388919.html