netty中pipeline的handler添加刪除分析
添加
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup,workGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>(){
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new MyServerHandler());
}
});
ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
channelFuture.channel().closeFuture().sync();
分析pipeline.addLast(new MyServerHandler())中的addLast。
首先通過(guò)channel拿到當(dāng)前的pipline, 拿到pipeline之后再為其添加handler, 因?yàn)?code>channel初始化默認(rèn)創(chuàng)建的是DefualtChannelPipeline
DefaultChannelPipeline.addLast(ChannelHandler... handlers)
public final ChannelPipeline addLast(ChannelHandler... handlers) {
return addLast(null, handlers);
}
public final ChannelPipeline addLast(EventExecutorGroup executor, ChannelHandler... handlers) {
if (handlers == null) {
throw new NullPointerException("handlers");
}
for (ChannelHandler h: handlers) {
if (h == null) {
break;
}
addLast(executor, null, h);
}
return this;
}
這里的handlers只有一個(gè)
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
//判斷handler是否被重復(fù)添加(1)
checkMultiplicity(handler);
//創(chuàng)建一個(gè)HandlerContext并添加到列表(2)
newCtx = newContext(group, filterName(name, handler), handler);
//添加HandlerContext(3)
addLast0(newCtx);
//是否已注冊(cè)
if (!registered) {
newCtx.setAddPending();
callHandlerCallbackLater(newCtx, true);
return this;
}
EventExecutor executor = newCtx.executor();
if (!executor.inEventLoop()) {
newCtx.setAddPending();
//回調(diào)用戶事件
executor.execute(new Runnable() {
@Override
public void run() {
callHandlerAdded0(newCtx);
}
});
return this;
}
}
//回調(diào)添加事件(4)
callHandlerAdded0(newCtx);
return this;
}
分為四個(gè)步驟:
- 重復(fù)添加驗(yàn)證
- 創(chuàng)建一個(gè)
HandlerContext并添加到列表 - 添加
context - 回調(diào)添加事件
checkMultiplicity(handler)重復(fù)添加驗(yàn)證
private static void checkMultiplicity(ChannelHandler handler) {
if (handler instanceof ChannelHandlerAdapter) {
ChannelHandlerAdapter h = (ChannelHandlerAdapter) handler;
if (!h.isSharable() && h.added) {
throw new ChannelPipelineException(
h.getClass().getName() +
" is not a @Sharable handler, so can't be added or removed multiple times.");
}
//滿足條件設(shè)置為true, 代表已添加
h.added = true;
}
}
- 首先判斷是不是
ChannelHandlerAdapter類型, 因?yàn)槲覀冏远x的handler通常會(huì)直接或者間接的繼承該接口, 所以這里為true拿到handler之后轉(zhuǎn)換成ChannelHandlerAdapter類型。 - 然后進(jìn)行條件判斷
if (!h.isSharable() && h.added)代表如果不是共享的handler, 并且是未添加狀態(tài), 則拋出異常。
isSharable()
public boolean isSharable() {
Class<?> clazz = getClass();
Map<Class<?>, Boolean> cache = InternalThreadLocalMap.get().handlerSharableCache();
Boolean sharable = cache.get(clazz);
if (sharable == null) {
//如果這個(gè)類注解了Sharable.class, 說(shuō)明這個(gè)類會(huì)被多個(gè)channel共享
sharable = clazz.isAnnotationPresent(Sharable.class);
cache.put(clazz, sharable);
}
return sharable;
}
- 首先拿到當(dāng)前
handler的class對(duì)象。 - 然后再?gòu)?code>netty自定義的一個(gè)
ThreadLocalMap對(duì)象中獲取一個(gè)盛放handler的class對(duì)象的map, 并獲取其value。 - 如果
value值為空, 則會(huì)判斷是否被Sharable注解, 并將自身handler的class對(duì)象和判斷結(jié)果存入map對(duì)象中, 最后返回判斷結(jié)果。 - 這說(shuō)明了被
Sharable注解的handler是一個(gè)共享handler。 - 從這個(gè)邏輯我們可以判斷, 共享對(duì)象是可以重復(fù)添加的。
回到DefaultChannelPipeline.addLast,如果是共享對(duì)象或者沒(méi)有被添加, 則將ChannelHandlerAdapter的added設(shè)置為true, 代表已添加分析完了重復(fù)添加驗(yàn)證, 回到addLast方法中, 我們看第二步, 創(chuàng)建一個(gè)HandlerContext并添加到列表
newCtx = newContext(group, filterName(name, handler), handler)
newCtx = newContext(group, filterName(name, handler), handler)
首先看filterName(name, handler)方法, 這個(gè)方法是判斷添加handler的name是否重復(fù)
filterName(name, handler)
首先看filterName(name, handler)方法, 這個(gè)方法是判斷添加handler的name是否重復(fù)
private String filterName(String name, ChannelHandler handler) {
if (name == null) {
//沒(méi)有名字創(chuàng)建默認(rèn)名字
return generateName(handler);
}
//檢查名字是否重復(fù)
checkDuplicateName(name);
return name;
}
因?yàn)槲覀兲砑?code>handler時(shí)候, 不一定會(huì)給handler命名, 所以這一步name有可能是null, 如果是null, 則創(chuàng)建一個(gè)默認(rèn)的名字, 這里創(chuàng)建名字的方法就不分析了
checkDuplicateName(name)
private void checkDuplicateName(String name) {
//不為空
if (context0(name) != null) {
throw new IllegalArgumentException("Duplicate handler name: " + name);
}
}
繼續(xù)跟進(jìn)分析context0(name)方法
context0(name)
private AbstractChannelHandlerContext context0(String name) {
//遍歷pipeline
AbstractChannelHandlerContext context = head.next;
while (context != tail) {
//發(fā)現(xiàn)name相同, 說(shuō)明存在handler
if (context.name().equals(name)) {
//返回
return context;
}
context = context.next;
}
return null;
}
這里的邏輯就是將pipeline中, 從head節(jié)點(diǎn)往下遍歷HandlerContext, 一直遍歷到tail, 如果發(fā)現(xiàn)名字相同則會(huì)認(rèn)為重復(fù)并返回HandlerContext對(duì)象。
繼續(xù)跟到newContext(group, filterName(name, handler), handler)方法中。
newContext(EventExecutorGroup group, String name, ChannelHandler handler)
private AbstractChannelHandlerContext newContext(EventExecutorGroup group, String name, ChannelHandler handler) {
return new DefaultChannelHandlerContext(this, childExecutor(group), name, handler);
}
可以看到創(chuàng)建了一個(gè)DefaultChannelHandlerContext對(duì)象, 構(gòu)造方法的參數(shù)中, 第一個(gè)this代表當(dāng)前的pipeline對(duì)象, group為null, 所以childExecutor(group)也會(huì)返回null, name為handler的名字, handler為新添加的handler對(duì)象
new DefaultChannelHandlerContext(this, childExecutor(group), name, handler)
DefaultChannelHandlerContext(
DefaultChannelPipeline pipeline, EventExecutor executor, String name, ChannelHandler handler) {
super(pipeline, executor, name, isInbound(handler), isOutbound(handler));
if (handler == null) {
throw new NullPointerException("handler");
}
this.handler = handler;
}
- 首先調(diào)用了父類的構(gòu)造方法, 之后將
handler賦值為自身handler的成員變量,HandlerConext和handler關(guān)系在此也展現(xiàn)了出來(lái), 是一種組合關(guān)系 - 父類的構(gòu)造方法, 有這么兩個(gè)參數(shù):
isInbound(handler),isOutbound(handler), 這兩個(gè)參數(shù)意思是判斷需要添加的handler是inboundHandler還是outBoundHandler
isInbound(handler)
private static boolean isInbound(ChannelHandler handler) {
return handler instanceof ChannelInboundHandler;
}
這里通過(guò)是否實(shí)現(xiàn)ChannelInboundHandler接口來(lái)判斷是否為inboundhandler
isOutbound(handler)
private static boolean isOutbound(ChannelHandler handler) {
return handler instanceof ChannelOutboundHandler;
}
通過(guò)判斷是否實(shí)現(xiàn)ChannelOutboundHandler接口判斷是否為outboundhandler
在跟到其父類AbstractChannelHandlerContext的構(gòu)造方法中
AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor, String name,
boolean inbound, boolean outbound) {
this.name = ObjectUtil.checkNotNull(name, "name");
this.pipeline = pipeline;
this.executor = executor;
this.inbound = inbound;
this.outbound = outbound;
ordered = executor == null || executor instanceof OrderedEventExecutor;
}
之前tail節(jié)點(diǎn)和head節(jié)點(diǎn)創(chuàng)建的時(shí)候也執(zhí)行到了這里,初始化了name, pipeline, 以及標(biāo)識(shí)添加的handler是inboundhanlder還是outboundhandler。
回到DefaultChannelPipeline.addLast,分析完了創(chuàng)建HandlerContext的相關(guān)邏輯, 我們繼續(xù)跟第三步, 添加HandlerContext
addLast0(newCtx)
private void addLast0(AbstractChannelHandlerContext newCtx) {
//拿到tail節(jié)點(diǎn)的前置節(jié)點(diǎn)
AbstractChannelHandlerContext prev = tail.prev;
//當(dāng)前節(jié)點(diǎn)的前置節(jié)點(diǎn)賦值為tail節(jié)點(diǎn)的前置節(jié)點(diǎn)
newCtx.prev = prev;
//當(dāng)前節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)賦值為tail節(jié)點(diǎn)
newCtx.next = tail;
//tail前置節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)賦值為當(dāng)前節(jié)點(diǎn)
prev.next = newCtx;
//tail節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)賦值為當(dāng)前節(jié)點(diǎn)
tail.prev = newCtx;
}
做了一個(gè)指針的指向操作, 將新添加的handlerConext放在tail節(jié)點(diǎn)之前, 之前tail節(jié)點(diǎn)的上一個(gè)節(jié)點(diǎn)之后, 如果是第一次添加handler, 那么添加后的結(jié)構(gòu)入下圖所示

添加完handler之后, 這里會(huì)判斷當(dāng)前channel是否已經(jīng)注冊(cè), 這部分邏輯之后再進(jìn)行分析,先接著繼續(xù)執(zhí)行。
之后會(huì)判斷當(dāng)前線程線程是否為eventLoop線程, 如果不是eventLoop線程, 就將添加回調(diào)事件封裝成task交給eventLoop線程執(zhí)行, 否則, 直接執(zhí)行添加回調(diào)事件callHandlerAdded0(newCtx)。
callHandlerAdded0(newCtx)
private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
try {
ctx.handler().handlerAdded(ctx);
ctx.setAddComplete();
} catch (Throwable t) {
/**
* 省略
* */
}
}
分析ctx.handler().handlerAdded(ctx),其中ctx是我們新創(chuàng)建的HandlerContext, 通過(guò)handler()方法拿到綁定的handler, 也就是新添加的handler, 然后執(zhí)行handlerAdded(ctx)方法, 如果我們沒(méi)有重寫(xiě)這個(gè)方法, 則會(huì)執(zhí)行父類的該方法。
ChannelHandlerAdapter.(ChannelHandlerContext ctx)
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
// NOOP
}
沒(méi)做任何操作, 也就是如果我們沒(méi)有重寫(xiě)該方法時(shí), 如果添加handler之后將不會(huì)做任何操作, 這里如果我們需要做一些業(yè)務(wù)邏輯, 可以通過(guò)重寫(xiě)該方法進(jìn)行實(shí)現(xiàn)
刪除
刪除的邏輯和添加的邏輯相同,區(qū)別刪除是將pipeline的雙向鏈表的節(jié)點(diǎn)去掉。這里就不詳細(xì)的分析。
以上就是netty中pipelinehandler添加刪除分析的詳細(xì)內(nèi)容,更多關(guān)于netty pipeline handler的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java字符串轉(zhuǎn)JSON簡(jiǎn)單代碼示例
這篇文章主要給大家介紹了關(guān)于java字符串轉(zhuǎn)JSON的相關(guān)資料,JSON?是一種輕量級(jí)的數(shù)據(jù)交換格式,常用于Web應(yīng)用程序中的數(shù)據(jù)傳輸,文中通過(guò)代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09
Java Web使用簡(jiǎn)單的批處理操作(記事本+Tomcat)
這篇文章主要介紹了Java Web使用簡(jiǎn)單的批處理操作 ,需要的朋友可以參考下2014-10-10
Java詳解ScriptEngine接口動(dòng)態(tài)執(zhí)行JS腳本
ScriptEngine是基本接口,其方法必須在本規(guī)范的每個(gè)實(shí)現(xiàn)中完全起作用。這些方法提供基本腳本功能。 寫(xiě)入這個(gè)簡(jiǎn)單接口的應(yīng)用程序可以在每個(gè)實(shí)現(xiàn)中進(jìn)行最少的修改。 它包括執(zhí)行腳本的方法,以及設(shè)置和獲取值的方法2022-08-08
關(guān)于BufferedReader的read()和readLine()的區(qū)別
這篇文章主要介紹了關(guān)于BufferedReader的read()和readLine()的區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
SpringBoot啟動(dòng)及自動(dòng)裝配原理過(guò)程詳解
這篇文章主要介紹了SpringBoot啟動(dòng)及自動(dòng)裝配原理過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04

