java 中 ChannelHandler的用法詳解
java 中 ChannelHandler的用法詳解
前言:
ChannelHandler處理一個(gè)I/O event或者攔截一個(gè)I/O操作,在它的ChannelPipeline中將其遞交給相鄰的下一個(gè)handler。
通過(guò)繼承ChannelHandlerAdapter來(lái)代替
因?yàn)檫@個(gè)接口有許多的方法需要實(shí)現(xiàn),你或許希望通過(guò)繼承ChannelHandlerAdapter來(lái)代替。
context對(duì)象
一個(gè)ChannelHandler和一個(gè)ChannelHandlerContext對(duì)象一起被提供。一個(gè)ChannelHander通過(guò)一個(gè)context對(duì)象和其所屬的那個(gè)ChannelPipeline進(jìn)行交互。使用context對(duì)象,ChannelHandler可以向上或者向下傳遞events,動(dòng)態(tài)地修改pipeline,或者存儲(chǔ)與handler相關(guān)的信息(使用AttributeKeys)。
狀態(tài)管理
一個(gè)ChannelHandler經(jīng)常需要存儲(chǔ)一些狀態(tài)相關(guān)的信息。最簡(jiǎn)單和推薦的方法是使用成員變量:
public interface Message {
// your methods here
}
public class DataServerHandler extends SimpleChannelInboundHandler<Message> {
private boolean loggedIn;
@Override
protected void messageReceived(ChannelHandlerContext ctx, Message message) {
Channel ch = e.getChannel();
if (message instanceof LoginMessage) {
authenticate((LoginMessage) message);
loggedIn = true;
} else (message instanceof GetDataMessage) {
if (loggedIn) {
ch.write(fetchSecret((GetDataMessage) message));
} else {
fail();
}
}
}
...
}
因?yàn)閔andler實(shí)例有一個(gè)狀態(tài)變量專注于一個(gè)連接,你必須為每一個(gè)handler實(shí)例創(chuàng)建一個(gè)新的handler實(shí)例,來(lái)避免競(jìng)態(tài)的情況以至于未認(rèn)證的客戶端可以獲得機(jī)密的信息:
// Create a new handler instance per channel.
// See ChannelInitializer.initChannel(Channel).
public class DataServerInitializer extends ChannelInitializer<Channel> {
@Override
public void initChannel(Channel channel) {
channel.pipeline().addLast("handler", new DataServerHandler());
}
}
使用AttributeKeys
雖然使用成員變量來(lái)保存一個(gè)handler的狀態(tài)是被推薦的,然而,由于一些原因你或許不想創(chuàng)建很多的handler實(shí)例。在這種情況下,你可以使用附在ChannelHandlerContext上的AttributeKeys:
public interface Message {
// your methods here
}
@Sharable
public class DataServerHandler extends SimpleChannelInboundHandler<Message> {
private final AttributeKey<Boolean> auth =
AttributeKey.valueOf("auth");
@Override
protected void messageReceived(ChannelHandlerContext ctx, Message message) {
Attribute<Boolean> attr = ctx.attr(auth);
Channel ch = ctx.channel();
if (message instanceof LoginMessage) {
authenticate((LoginMessage) o);
attr.set(true);
} else (message instanceof GetDataMessage) {
if (Boolean.TRUE.equals(attr.get())) {
ch.write(fetchSecret((GetDataMessage) o));
} else {
fail();
}
}
}
...
}
現(xiàn)在handler的狀態(tài)被附在了ChannelHandlerContext上了,你可以添加同樣的Handler實(shí)例到不同的pipeline上:
public class DataServerInitializer extends ChannelInitializer<Channel> {
private static final DataServerHandler SHARED = new DataServerHandler();
@Override
public void initChannel(Channel channel) {
channel.pipeline().addLast("handler", SHARED);
}
}
@Sharable 注解
在上面使用AttributeKey的例子中,你應(yīng)該已經(jīng)注意到了@Sharable注解。
如果一個(gè)ChannelHandler被注解為@Sharable,那意味著你可以只創(chuàng)建一個(gè)handler實(shí)例,并把它添加到一個(gè)或多個(gè)ChannelPipeline中多次,并不用考慮競(jìng)態(tài)的情況。
如果這個(gè)注解沒(méi)有指定,你就只能為每次需要添加到pipeline中的handler,每次創(chuàng)建一個(gè)新的實(shí)例。因?yàn)樗蟹枪蚕淼臓顟B(tài),比如:成員變量。
如有疑問(wèn)請(qǐng)留言或者到本站社區(qū)交流討論,感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
java如何讀取resources目錄和同級(jí)目錄文件
介紹了Java中讀取resources目錄和同級(jí)目錄文件的方法,并討論了在IDE和發(fā)布環(huán)境中可能遇到的問(wèn)題,通過(guò)測(cè)試發(fā)現(xiàn),執(zhí)行目錄可能會(huì)影響文件讀取,建議在使用`user.dir`時(shí)注意jar包的運(yùn)行目錄問(wèn)題2024-12-12
maven deploy時(shí)報(bào)錯(cuò)的解決方法
這篇文章主要介紹了maven deploy時(shí)報(bào)錯(cuò)的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
Java使用多線程批次查詢大量數(shù)據(jù)(Callable返回?cái)?shù)據(jù))方式
今天給大家分享Java使用多線程批次查詢大量數(shù)據(jù)(Callable返回?cái)?shù)據(jù))方式,多線程有好幾種方式,今天說(shuō)的方式比較好,實(shí)現(xiàn)Callable<> 這種方式能返回查詢的數(shù)據(jù),加上Future異步獲取方式,查詢效率大大加快,感興趣的朋友一起看看吧2023-11-11
SpringBoot整合EasyExcel實(shí)現(xiàn)大規(guī)模數(shù)據(jù)的并行導(dǎo)出與壓縮下載
在 Spring Boot 應(yīng)用中,整合 EasyExcel 實(shí)現(xiàn)并行導(dǎo)出數(shù)據(jù)并進(jìn)行 Zip 壓縮下載可以極大地提高數(shù)據(jù)處理效率和用戶體驗(yàn),文中通過(guò)代碼示例介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下2024-10-10
java實(shí)現(xiàn)的小時(shí)鐘示例分享
這篇文章主要介紹了java實(shí)現(xiàn)的小時(shí)鐘示例,需要的朋友可以參考下2014-02-02
Java啟動(dòng)Tomcat的實(shí)現(xiàn)步驟
本文主要介紹了Java啟動(dòng)Tomcat的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
Java實(shí)現(xiàn)滑動(dòng)驗(yàn)證碼的示例代碼
這篇文章主要為大家介紹了如何用Java語(yǔ)言實(shí)現(xiàn)滑動(dòng)驗(yàn)證碼的生成,項(xiàng)目采用了springboot,maven等技術(shù),感興趣的小伙伴可以跟隨小編學(xué)習(xí)一下2022-02-02

