51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

米哈游1面:Netty 包含哪些经典的设计模式?

你好,我是猿java。

Netty 是一个优秀的、高性能、异步的事件驱动网络应用框架,它内部使用了许多经典的设计模式。这篇文章,我们来详细分析 Netty到底使用了哪些优秀的设计模式,并且结合 Netty 的具体实现来探讨这些模式的应用。

这篇文章,我们分析 8个有代表性的模式:

  1. 责任链模式

  2. 观察者模式

  3. 工厂模式

  4. 适配器模式

  5. 策略模式

  6. 原型模式

  7. 单例模式

  8. 模板方法模式

  9. 责任链模式 {#1-责任链模式} ===================

概念:
责任链模式(Chain of Responsibility)用于将请求沿着处理链传播,每个对象都有机会处理请求或将其传递给下一个对象。
img

Netty 中的应用:
Netty 的 ChannelPipelineChannelHandler 正是责任链模式的经典实现。ChannelPipeline 是一组互相连接的 ChannelHandler 对象,每个 ChannelHandler 执行对数据流的处理。

实现案例:

  • 在 Netty 中,ChannelPipeline 提供了一组按顺序工作的 ChannelHandler,可分为入站(inbound)和出站(outbound)。
  • 当接收到数据时,它会沿入站处理链传播,各个入站 ChannelHandler 依次处理该数据(如解码、业务逻辑处理等)。
  • 当发送数据时,它会沿出站处理链传播,各个出站 ChannelHandler 依次处理该数据(如编码、压缩等)。

代码示例:

|-----------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 | ChannelPipeline pipeline = channel.pipeline(); pipeline.addLast(new DecoderHandler()); pipeline.addLast(new BusinessLogicHandler()); pipeline.addLast(new EncoderHandler()); |

每个处理器都会处理其关心的部分,并将其余的事情交给链内的下一个处理器。

  1. 观察者模式 {#2-观察者模式} ===================

概念:
观察者模式(Observer)定义了对象之间的一对多依赖关系,当目标对象状态发生改变时,其依赖者(观察者)会收到通知并自动更新。
img
Netty 中的应用:
Netty 的事件驱动模型通过观察者模式实现。当 Selector 检测到特定事件(如 readwrite 准备完成)后会通知对应的 ChannelChannel 会触发事件并将任务提交到合适的处理器执行。

实现案例:

  • ChannelFuture 是 Netty 中观察者模式的典型应用,例如,当你向服务器发送数据时,可以通过 ChannelFuture 注册监听器,来监控数据发送是否完成。
  • 当操作完成时,监听器会被通知从而执行用户定义的回调逻辑。

代码示例:

|---------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 | ChannelFuture future = channel.writeAndFlush(message); future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess()) { System.out.println("Write successful!"); } else { System.out.println("Write failed: " + future.cause()); } } }); |

ChannelFutureListener 是典型的观察者,当 ChannelFuture 的状态变化时会收到通知。

  1. 工厂模式 {#3-工厂模式} =================

概念:
工厂模式(Factory)用于创建对象的实例,屏蔽了对象创建的复杂性。

img

Netty 中的应用:
Netty 使用工厂模式隐藏了创建复杂对象的细节,常见的是 EventLoopGroupBootstrap 等组件。

实现案例:

  • EventLoopGroup 是执行事件循环的关键组件,Netty 提供了多种实现(如 NIO 的 NioEventLoopGroup 和 Epoll 的 EpollEventLoopGroup),用户可以通过抽象工厂模式指定自己需要的实现。
  • BootstrapServerBootstrap 也是工厂模式的经典应用,它们用于构造客户端和服务端配置。

代码示例:

|------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 | EventLoopGroup group = new NioEventLoopGroup(); Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new MyHandler()); } }); |

用户只需要调用 Bootstrap 的方法即可完成工厂的配置,隐藏了复杂的配置逻辑。

  1. 适配器模式 {#4-适配器模式} ===================

概念:
适配器模式(Adapter)用来将一个类的接口转换为另一个接口,以实现接口之间的兼容。

img

Netty 中的应用:
Netty 的 ChannelHandlerAdapterChannelInboundHandlerAdapter 是典型的适配器模式应用,它们简化了 ChannelHandler 的实现。

实现案例:

  • Netty 的 ChannelHandler 提供了很多接口方法,但用户可能只需要实现一小部分逻辑。在这种情况下,用户无需全部实现所有方法,可以继承 ChannelInboundHandlerAdapterChannelOutboundHandlerAdapter 来简化代码。

代码示例:

|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 | public class MyHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("Message received: " + msg); ctx.fireChannelRead(msg); } } |

通过适配器,用户不需要实现 ChannelHandler 的所有方法,同时保留了灵活性。

  1. 策略模式 {#5-策略模式} =================

概念:
策略模式(Strategy)将一组算法封装起来,使得它们可以互换,同时将算法的选择独立于使用这些算法的客户。

img

Netty 中的应用:
Netty 在其 EventLoopGroup 和处理 IO 的任务分配中采用了策略模式。通过抽象的 EventLoop,Netty 支持多种不同的多路复用机制(如 NIO、Epoll 等)。

实现案例:

  • EventLoopGroup 支持多种实现,并根据运行环境动态选择策略,例如在 Linux 平台优先选择 Epoll。
  • Netty 的序列化与解码器也使用了策略模式,不同的序列化方式可以互相替换(如 protobuf、JSON 等)。

代码示例:

|-----------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 | EventLoopGroup group = new EpollEventLoopGroup(); // Linux 平台下的高性能实现 Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group) .channel(EpollSocketChannel.class); |

用户可以灵活替换实现以适配特定需求。

  1. 原型模式 {#6-原型模式} =================

概念:
原型模式 (Prototype)通过克隆的方式创建对象,而不是直接实例化。

img

Netty 中的应用:
Netty 的缓冲区分配(ByteBufAllocator)中使用了原型模式。为了减少内存分配和回收的开销,Netty 提供了池化的缓冲区,通过克隆和回收来重复利用缓冲区。

实现案例:

  • PooledByteBufAllocator 负责提供缓冲区,其内部维护了一系列固定大小的内存块,用于内存分配和回收。
  • 使用原型模式减少了频繁的内存分配成本。
  1. 单例模式 {#7-单例模式} =================

概念:
单例模式(Singleton)保证一个类只存在一个实例,并提供全局访问点。

img

Netty 中的应用:
Netty 中某些共享的组件采用单例模式,例如 Unpooled 类和一些内部工具类。

实现案例:

  • Unpooled 是非池化缓冲区的工厂类,它使用单例模式提供缓冲区操作的统一入口。

代码示例:

|-----------|---------------------------------------------| | 1 | ByteBuf buf = Unpooled.buffer(256); |

  1. 模板方法模式 {#8-模板方法模式} =====================

概念:
模板方法模式(Template Method)允许在基类定义操作的框架,而将具体实现延迟到子类。

img

Netty 中的应用:
Netty 的很多组件都提供了模板方法模式的实现,例如 ChannelInitializer 用于设置 ChannelPipeline

实现案例:

  • 用户通过继承 ChannelInitializer 定义自己的逻辑,而底层框架负责调用和执行。

代码示例:

|---------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 | public class MyChannelInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new MyHandler()); } } |

  1. 总结 {#9-总结} =============

这篇文章,我们详细地分析了 Netty 包含的经典设计模式,并结合 Netty 的具体实现来探讨这些模式的应用。因为篇幅有限,我们只分析了 8种有代表性的模型,但是 Netty的设计模式绝不仅仅只有这些,它们都是经典的设计模式。作为Java领域一款经典的网络通信工具,Netty绝对值得我们花时间去琢磨。

  1. 学习交流 {#10-学习交流} ===================
赞(0)
未经允许不得转载:工具盒子 » 米哈游1面:Netty 包含哪些经典的设计模式?