米哈游1面:Netty 包含哪些经典的设计模式?
你好,我是猿java。
Netty 是一个优秀的、高性能、异步的事件驱动网络应用框架,它内部使用了许多经典的设计模式。这篇文章,我们来详细分析 Netty到底使用了哪些优秀的设计模式,并且结合 Netty 的具体实现来探讨这些模式的应用。
这篇文章,我们分析 8个有代表性的模式:
- 责任链模式
- 观察者模式
- 工厂模式
- 适配器模式
- 策略模式
- 原型模式
- 单例模式
- 模板方法模式
1. 责任链模式
概念:
责任链模式(Chain of Responsibility)用于将请求沿着处理链传播,每个对象都有机会处理请求或将其传递给下一个对象。
Netty 中的应用:
Netty 的 ChannelPipeline
和 ChannelHandler
正是责任链模式的经典实现。ChannelPipeline
是一组互相连接的 ChannelHandler
对象,每个 ChannelHandler
执行对数据流的处理。
实现案例:
- 在 Netty 中,
ChannelPipeline
提供了一组按顺序工作的ChannelHandler
,可分为入站(inbound)和出站(outbound)。 - 当接收到数据时,它会沿入站处理链传播,各个入站
ChannelHandler
依次处理该数据(如解码、业务逻辑处理等)。 - 当发送数据时,它会沿出站处理链传播,各个出站
ChannelHandler
依次处理该数据(如编码、压缩等)。
代码示例:
1 | ChannelPipeline pipeline = channel.pipeline(); |
每个处理器都会处理其关心的部分,并将其余的事情交给链内的下一个处理器。
2. 观察者模式
概念:
观察者模式(Observer)定义了对象之间的一对多依赖关系,当目标对象状态发生改变时,其依赖者(观察者)会收到通知并自动更新。
Netty 中的应用:
Netty 的事件驱动模型通过观察者模式实现。当 Selector
检测到特定事件(如 read
或 write
准备完成)后会通知对应的 Channel
。Channel
会触发事件并将任务提交到合适的处理器执行。
实现案例:
ChannelFuture
是 Netty 中观察者模式的典型应用,例如,当你向服务器发送数据时,可以通过ChannelFuture
注册监听器,来监控数据发送是否完成。- 当操作完成时,监听器会被通知从而执行用户定义的回调逻辑。
代码示例:
1 | ChannelFuture future = channel.writeAndFlush(message); |
ChannelFutureListener
是典型的观察者,当 ChannelFuture
的状态变化时会收到通知。
3. 工厂模式
概念:
工厂模式(Factory)用于创建对象的实例,屏蔽了对象创建的复杂性。
Netty 中的应用:
Netty 使用工厂模式隐藏了创建复杂对象的细节,常见的是 EventLoopGroup
和 Bootstrap
等组件。
实现案例:
EventLoopGroup
是执行事件循环的关键组件,Netty 提供了多种实现(如 NIO 的NioEventLoopGroup
和 Epoll 的EpollEventLoopGroup
),用户可以通过抽象工厂模式指定自己需要的实现。Bootstrap
和ServerBootstrap
也是工厂模式的经典应用,它们用于构造客户端和服务端配置。
代码示例:
1 | EventLoopGroup group = new NioEventLoopGroup(); |
用户只需要调用 Bootstrap 的方法即可完成工厂的配置,隐藏了复杂的配置逻辑。
4. 适配器模式
概念:
适配器模式(Adapter)用来将一个类的接口转换为另一个接口,以实现接口之间的兼容。
Netty 中的应用:
Netty 的 ChannelHandlerAdapter
和 ChannelInboundHandlerAdapter
是典型的适配器模式应用,它们简化了 ChannelHandler
的实现。
实现案例:
- Netty 的
ChannelHandler
提供了很多接口方法,但用户可能只需要实现一小部分逻辑。在这种情况下,用户无需全部实现所有方法,可以继承ChannelInboundHandlerAdapter
或ChannelOutboundHandlerAdapter
来简化代码。
代码示例:
1 | public class MyHandler extends ChannelInboundHandlerAdapter { |
通过适配器,用户不需要实现 ChannelHandler
的所有方法,同时保留了灵活性。
5. 策略模式
概念:
策略模式(Strategy)将一组算法封装起来,使得它们可以互换,同时将算法的选择独立于使用这些算法的客户。
Netty 中的应用:
Netty 在其 EventLoopGroup
和处理 IO 的任务分配中采用了策略模式。通过抽象的 EventLoop
,Netty 支持多种不同的多路复用机制(如 NIO、Epoll 等)。
实现案例:
EventLoopGroup
支持多种实现,并根据运行环境动态选择策略,例如在 Linux 平台优先选择 Epoll。- Netty 的序列化与解码器也使用了策略模式,不同的序列化方式可以互相替换(如 protobuf、JSON 等)。
代码示例:
1 | EventLoopGroup group = new EpollEventLoopGroup(); // Linux 平台下的高性能实现 |
用户可以灵活替换实现以适配特定需求。
6. 原型模式
概念:
原型模式 (Prototype)通过克隆的方式创建对象,而不是直接实例化。
Netty 中的应用:
Netty 的缓冲区分配(ByteBufAllocator
)中使用了原型模式。为了减少内存分配和回收的开销,Netty 提供了池化的缓冲区,通过克隆和回收来重复利用缓冲区。
实现案例:
PooledByteBufAllocator
负责提供缓冲区,其内部维护了一系列固定大小的内存块,用于内存分配和回收。- 使用原型模式减少了频繁的内存分配成本。
7. 单例模式
概念:
单例模式(Singleton)保证一个类只存在一个实例,并提供全局访问点。
Netty 中的应用:
Netty 中某些共享的组件采用单例模式,例如 Unpooled
类和一些内部工具类。
实现案例:
Unpooled
是非池化缓冲区的工厂类,它使用单例模式提供缓冲区操作的统一入口。
代码示例:
1 | ByteBuf buf = Unpooled.buffer(256); |
8. 模板方法模式
概念:
模板方法模式(Template Method)允许在基类定义操作的框架,而将具体实现延迟到子类。
Netty 中的应用:
Netty 的很多组件都提供了模板方法模式的实现,例如 ChannelInitializer
用于设置 ChannelPipeline
。
实现案例:
- 用户通过继承
ChannelInitializer
定义自己的逻辑,而底层框架负责调用和执行。
代码示例:
1 | public class MyChannelInitializer extends ChannelInitializer<SocketChannel> { |
9. 总结
这篇文章,我们详细地分析了 Netty 包含的经典设计模式,并结合 Netty 的具体实现来探讨这些模式的应用。因为篇幅有限,我们只分析了 8种有代表性的模型,但是 Netty的设计模式绝不仅仅只有这些,它们都是经典的设计模式。作为Java领域一款经典的网络通信工具,Netty绝对值得我们花时间去琢磨。
10. 学习交流
如果你觉得文章有帮助,请帮忙转发给更多的好友,或关注公众号:猿java,持续输出硬核文章。