跳到主要内容

如何封装一个非阻塞式 Java 网络库

1. 前言

到目前为止,我们已经学完了 Java 网络编程的所有关键知识点,如果能将这些知识点灵活应用到项目中,那再好不过了。本小节将从实战的角度出发,展示如何基于 Java NIO 封装一个非阻塞式网络库。核心是采用事件反应器模型,将复杂的 SocketChannel、ServerSocketChannel、ByteBuffer、Selector 进行抽象,将繁琐的数据读写操作加以封装,以便应用程序调用。

本项目提供的完整代码路径:

https://github.com/haska1025/imooc-sock-core-tech/tree/master/java_netprogramming

2. 系统类图

在 OOD 的思想体系下,现实世界中无论是具体的、还是抽象的事物,都是对象,现实世界就是由对象组成的。对象有自己的属性行为,对象之间可以产生联系。把具有相同属性行为的对象叫做同一类对象,抽象出。OOD 的思想非常符合人的思维方式,更容易建模和抽象。如果你对 OOD 不是很熟悉的话,可以查阅相关资料学习。

我们现在的工作是要把 Java NIO 中的各个组件加以抽象,抽象出一个或若干个类,通过 UML 展现出来,类图如下:

图片描述

下来我们就解释一下以上几个接口和实现类的功能:

类名功能
PollerJava NIO Selector 事件多路复用机制的封装,实现事件循环机制,是一个事件反应器,是一个功能实现类
IOHandler是 Poller 的配套类,响应accept、connect、read、write事件,是一个 Java 接口
SocketHandler是一个功能类,实现了 IOHandler 接口,将一些通用的逻辑加以封装
Acceptor实现 TCP 服务器监听功能,继承自 SocketHandler
TcpHandlerTCP 客户端、服务器逻辑的封装,继承自 SocketHandler。主要完成客户端连接,服务器接收新连接,数据收发,关闭连接的功能
IOAdapter事件循环机制向应用层提供的一个回调接口,一般由 IOHandler 调用
AbstractAdapter是一个 Java 接口,主要完成通用逻辑,实现了 IOAdapter 接口
Listener事件监听接口,主要实现线程切换的功能
CustomEventObject代表一个具体事件,是 Listener 的配套类
IOThread对 Java 线程的封装,聚合了 Poller 功能。我们说过 Java 的 Selector 其实是同步的,需要一个线程调用 select 监听事件
ThreadPool对 IOThread 的封装,提供线程池功能

3. 接口设计

软件的接口是指软件模块对外提供的一组函数或者方法,目的是让别的模块访问本模块的功能,以达到组件复用的目的。根据模块逻辑复杂度的不同,接口由分为:系统接口、子系统接口、模块接口、子模块接口、类接口。关于模块、子模块、类的应用都非常灵活,我们这里认为类就是最小的模块。

本小节所说的接口是指 Java 接口。我们抽象了三个 Java 接口:Listener、IOHandler、IOAdapter,还有一个功能类 Poller。现在对每个接口中的方法加以说明:

  • Poller
类名接口名描述
Pollerregister将 IOHandler 实例添加到 Poller
start启动一个 Poller 实例
close停止一个 Poller 实例
pollPoller 进入事件循环
  • IOHandler
类名接口名描述
IOHandlerhandle_read是一个回调方法,当 Poller 监听到某个 IOHandler 注册的事件触发时,调用 handle_read
handle_write是一个回调方法,当 Poller 监听到某个 IOHandler 注册的事件触发时,调用 handle_write
handle_accept是一个回调方法,当 Poller 监听到某个 IOHandler 注册的accept事件触发时,调用 handle_accept
handle_connected是一个回调方法,当 Poller 监听到某个 IOHandler 注册的connected事件触发时,调用 handle_connected
getSocketChannel用于获取 IOHandler 对应的 SocketChannel 对象

IOHandler 是一个抽象接口,TcpHandler 需要实现此接口,当然你也可以实现其他协议,只需要扩展 IOHandler 的接口即可。

  • IOAdapter
类名接口名描述
IOAdapteronAccept当 IOHandler 收到一个新的 TCP 连接时,在 handle_read 中回调此方法
onConnected当 io_hanIOHandlerdler 完成异步连接时,在 handle_connected 中回调此方法
onReadIOHandler 会在 handle_read 中回调此方法
onWriteIOHandler 会在 handle_write 中回调此方法
onCloseIOHandler 收到连接被关闭时,回调此方法
setSocketHandler向 IOAdapter 设置一个 IOHandler 对象

应用层需要实现 IOAdapter 的接口,并且要覆盖接口中的方法,完成数据收发。

  • Listener
类名接口名描述
Listenerprocess处理异步事件

4. 总结

本小节主要是将前面小节介绍的 Java NIO 相关模块进行一个抽象,形成一个非阻塞的 Java 网络库。采用的设计思想就是依赖倒转,将复杂的网络编程细节进行封装,让应用程序员不需要关注这些复杂的机制。

我们抽象出了一组接口和一组功能类,并对类的功能和接口中的方法进行了一一说明。本小节可以说是对整个系列内容的总结和实践。