米哈游一面:Netty 采用了哪些經(jīng)典的設計模式?
Netty 是一個優(yōu)秀的、高性能、異步的事件驅(qū)動網(wǎng)絡應用框架,它內(nèi)部使用了許多經(jīng)典的設計模式。這篇文章,我們來詳細分析 Netty到底使用了哪些優(yōu)秀的設計模式,并且結(jié)合 Netty 的具體實現(xiàn)來探討這些模式的應用。
1. 責任鏈模式
(1) 概念:
責任鏈模式(Chain of Responsibility)用于將請求沿著處理鏈傳播,每個對象都有機會處理請求或?qū)⑵鋫鬟f給下一個對象。
(2) Netty 中的應用:
Netty 的 ChannelPipeline 和 ChannelHandler 正是責任鏈模式的經(jīng)典實現(xiàn)。ChannelPipeline 是一組互相連接的 ChannelHandler 對象,每個 ChannelHandler 執(zhí)行對數(shù)據(jù)流的處理。
(3) 實現(xiàn)案例:
- 在 Netty 中,ChannelPipeline 提供了一組按順序工作的 ChannelHandler,可分為入站(inbound)和出站(outbound)。
- 當接收到數(shù)據(jù)時,它會沿入站處理鏈傳播,各個入站 ChannelHandler 依次處理該數(shù)據(jù)(如解碼、業(yè)務邏輯處理等)。
- 當發(fā)送數(shù)據(jù)時,它會沿出站處理鏈傳播,各個出站 ChannelHandler 依次處理該數(shù)據(jù)(如編碼、壓縮等)。
(4) 代碼示例:
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(new DecoderHandler());
pipeline.addLast(new BusinessLogicHandler());
pipeline.addLast(new EncoderHandler());
每個處理器都會處理其關(guān)心的部分,并將其余的事情交給鏈內(nèi)的下一個處理器。
2. 觀察者模式
(1) 概念:
觀察者模式(Observer)定義了對象之間的一對多依賴關(guān)系,當目標對象狀態(tài)發(fā)生改變時,其依賴者(觀察者)會收到通知并自動更新。
(2) Netty 中的應用:
Netty 的事件驅(qū)動模型通過觀察者模式實現(xiàn)。當 Selector 檢測到特定事件(如 read 或 write 準備完成)后會通知對應的 Channel。Channel 會觸發(fā)事件并將任務提交到合適的處理器執(zhí)行。
(3) 實現(xiàn)案例:
- ChannelFuture 是 Netty 中觀察者模式的典型應用,例如,當你向服務器發(fā)送數(shù)據(jù)時,可以通過 ChannelFuture 注冊監(jiān)聽器,來監(jiān)控數(shù)據(jù)發(fā)送是否完成。
- 當操作完成時,監(jiān)聽器會被通知從而執(zhí)行用戶定義的回調(diào)邏輯。
(4) 代碼示例:
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 的狀態(tài)變化時會收到通知。
3. 工廠模式
(1) 概念:
工廠模式(Factory)用于創(chuàng)建對象的實例,屏蔽了對象創(chuàng)建的復雜性。
(2) Netty 中的應用:
Netty 使用工廠模式隱藏了創(chuàng)建復雜對象的細節(jié),常見的是 EventLoopGroup 和 Bootstrap 等組件。
(3) 實現(xiàn)案例:
- EventLoopGroup 是執(zhí)行事件循環(huán)的關(guān)鍵組件,Netty 提供了多種實現(xiàn)(如 NIO 的 NioEventLoopGroup 和 Epoll 的 EpollEventLoopGroup),用戶可以通過抽象工廠模式指定自己需要的實現(xiàn)。
- Bootstrap 和 ServerBootstrap 也是工廠模式的經(jīng)典應用,它們用于構(gòu)造客戶端和服務端配置。
(4) 代碼示例:
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());
}
});
用戶只需要調(diào)用 Bootstrap 的方法即可完成工廠的配置,隱藏了復雜的配置邏輯。
4. 適配器模式
(1) 概念:
適配器模式(Adapter)用來將一個類的接口轉(zhuǎn)換為另一個接口,以實現(xiàn)接口之間的兼容。
(2) Netty 中的應用:
Netty 的 ChannelHandlerAdapter 和 ChannelInboundHandlerAdapter 是典型的適配器模式應用,它們簡化了 ChannelHandler 的實現(xiàn)。
(3) 實現(xiàn)案例:
Netty 的 ChannelHandler 提供了很多接口方法,但用戶可能只需要實現(xiàn)一小部分邏輯。在這種情況下,用戶無需全部實現(xiàn)所有方法,可以繼承 ChannelInboundHandlerAdapter 或 ChannelOutboundHandlerAdapter 來簡化代碼。
(4) 代碼示例:
public class MyHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("Message received: " + msg);
ctx.fireChannelRead(msg);
}
}
通過適配器,用戶不需要實現(xiàn) ChannelHandler 的所有方法,同時保留了靈活性。
5. 策略模式
(1) 概念:
策略模式(Strategy)將一組算法封裝起來,使得它們可以互換,同時將算法的選擇獨立于使用這些算法的客戶。
(2) Netty 中的應用:
Netty 在其 EventLoopGroup 和處理 IO 的任務分配中采用了策略模式。通過抽象的 EventLoop,Netty 支持多種不同的多路復用機制(如 NIO、Epoll 等)。
(3) 實現(xiàn)案例:
- EventLoopGroup 支持多種實現(xiàn),并根據(jù)運行環(huán)境動態(tài)選擇策略,例如在 Linux 平臺優(yōu)先選擇 Epoll。
- Netty 的序列化與解碼器也使用了策略模式,不同的序列化方式可以互相替換(如 protobuf、JSON 等)。
(4) 代碼示例:
EventLoopGroup group = new EpollEventLoopGroup(); // Linux 平臺下的高性能實現(xiàn)
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(EpollSocketChannel.class);
用戶可以靈活替換實現(xiàn)以適配特定需求。
6. 原型模式
(1) 概念:
原型模式 (Prototype)通過克隆的方式創(chuàng)建對象,而不是直接實例化。
(2) Netty 中的應用:
Netty 的緩沖區(qū)分配(ByteBufAllocator)中使用了原型模式。為了減少內(nèi)存分配和回收的開銷,Netty 提供了池化的緩沖區(qū),通過克隆和回收來重復利用緩沖區(qū)。
(3) 實現(xiàn)案例:
- PooledByteBufAllocator 負責提供緩沖區(qū),其內(nèi)部維護了一系列固定大小的內(nèi)存塊,用于內(nèi)存分配和回收。
- 使用原型模式減少了頻繁的內(nèi)存分配成本。
7. 單例模式
(1) 概念:
單例模式(Singleton)保證一個類只存在一個實例,并提供全局訪問點。
(2) Netty 中的應用:
Netty 中某些共享的組件采用單例模式,例如 Unpooled 類和一些內(nèi)部工具類。
(3) 實現(xiàn)案例:
Unpooled 是非池化緩沖區(qū)的工廠類,它使用單例模式提供緩沖區(qū)操作的統(tǒng)一入口。
(4) 代碼示例:
ByteBuf buf = Unpooled.buffer(256);
8. 模板方法模式
(1) 概念:
模板方法模式(Template Method)允許在基類定義操作的框架,而將具體實現(xiàn)延遲到子類。
(2) Netty 中的應用:
Netty 的很多組件都提供了模板方法模式的實現(xiàn),例如 ChannelInitializer 用于設置 ChannelPipeline。
(3) 實現(xiàn)案例:
用戶通過繼承 ChannelInitializer 定義自己的邏輯,而底層框架負責調(diào)用和執(zhí)行。
(4) 代碼示例:
public class MyChannelInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new MyHandler());
}
}
9. 總結(jié)
這篇文章,我們詳細地分析了 Netty 包含的經(jīng)典設計模式,并結(jié)合 Netty 的具體實現(xiàn)來探討這些模式的應用。因為篇幅有限,我們只分析了 8種有代表性的模型,但是 Netty的設計模式絕不僅僅只有這些,它們都是經(jīng)典的設計模式。作為Java領(lǐng)域一款經(jīng)典的網(wǎng)絡通信工具,Netty絕對值得我們花時間去琢磨。