5.Handler業務處理器
在Reactor反應器經典模型中,反應器查詢到IO事件後,分發到Handler業務處理器,由Handler完成IO操作和業務處理。整個的IO處理操作環節包括:從通道讀數據包、數據包解碼、業務處理、目標數據編碼、把數據包寫到通道,然後由通道發送到對端
用戶程序主要在Handler業務處理器中,Handler涉及的環節爲:數據包解碼、業務處理、目標數據編碼、把數據包寫到通道中。
從應用程序開發人員的角度來看,有入站和出站兩種類型操作。
· 入站處理,觸發的方向爲:自底向上,Netty的內部(如通道)到ChannelInboundHandler入站處理器。
· 出站處理,觸發的方向爲:自頂向下,從ChannelOutboundHandler出站處理器到Netty的內部(如通道)。
-
ChannelInboundHandler通道入站處理器
-
ChannelOutboundHandler通道出站處理器
5.1ChannelInitializer通道初始化處理器
通道和Handler業務處理器的關係是:一條Netty的通道擁有一條Handler業務處理器流水線,負責裝配自己的Handler業務處理器
如果向流水線中裝配業務處理器呢?這就得藉助通道的初始化類——ChannelInitializer。
- initChannel()方法是ChannelInitializer定義的一個抽象方法,這個抽象方法需要開發人員自己實現。在父通道調用initChannel()方法時,會將新接收的通道作爲參數,傳遞給initChannel()方法。initChannel()方法內部大致的業務代碼是:拿到新連接通道作爲實際參數,往它的流水線中裝配Handler業務處理器。
5.2ChannelInboundHandler的生命週期
ChannelInboundHandler的生命週期分2類:
- 生命週期方法
(1)handlerAdded() :當業務處理器被加入到流水線後,此方法被回調。也就是在完成ch.pipeline().addLast(handler)語句之後,會回調handlerAdded()。
(2)channelRegistered():當通道成功綁定一個NioEventLoop線程後,會通過流水線回調所有業務處理器的channelRegistered()方法。(3)channelActive():當通道激活成功後,會通過流水線回調所有業務處理器的channelActive()方法。通道激活成功指的是,所有的業務處理器添加、註冊的異步任務完成,並且NioEventLoop線程綁定的異步任務完成。(4)channelInactive():當通道的底層連接已經不是ESTABLISH狀態,或者底層連接已經關閉時,會首先回調所有業務處理器的channelInactive()方法。
(5)channelUnregistered():通道和NioEventLoop線程解除綁定,移除掉對這條通道的事件處理之後,回調所有業務處理器的channelUnregistered ()方法。
(6)handlerRemoved():最後,Netty會移除掉通道上所有的業務處理器,並且回調所有的業務處理器的handlerRemoved()方法。
-入棧回調方法
(1)channelRead():有數據包入站,通道可讀。流水線會啓動入站處理流程,從前向後,入站處理器的channelRead()方法會被依次回調到。
(2)channelReadComplete():流水線完成入站處理後,會從前向後,依次回調每個入站處理器的channelReadComplete()方法,表示數據讀取完畢。
5.3代碼示例
public class InHandlerDemo extends ChannelInboundHandlerAdapter {
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
Logger.info("被調用:handlerAdded()");
super.handlerAdded(ctx);
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
Logger.info("被調用:channelRegistered()");
super.channelRegistered(ctx);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Logger.info("被調用:channelActive()");
super.channelActive(ctx);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Logger.info("被調用:channelRead()");
super.channelRead(ctx, msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
Logger.info("被調用:channelReadComplete()");
super.channelReadComplete(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
Logger.info("被調用:channelInactive()");
super.channelInactive(ctx);
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
Logger.info("被調用: channelUnregistered()");
super.channelUnregistered(ctx);
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
Logger.info("被調用:handlerRemoved()");
super.handlerRemoved(ctx);
}
}
測試類
public class InHandlerDemoTester {
@Test
public void testInHandlerLifeCircle() {
final InHandlerDemo inHandler = new InHandlerDemo();
//初始化處理器
ChannelInitializer i = new ChannelInitializer<EmbeddedChannel>() {
@Override
protected void initChannel(EmbeddedChannel ch) {
ch.pipeline().addLast(inHandler);
}
};
//創建嵌入式通道
EmbeddedChannel channel = new EmbeddedChannel(i);
ByteBuf buf = Unpooled.buffer();
buf.writeInt(1);
//模擬入站,寫一個入站包
channel.writeInbound(buf);
channel.flush();
//模擬入站,再寫一個入站包
channel.writeInbound(buf);
channel.flush();
//通道關閉
channel.close();
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}