java 中 ChannelHandler的用法詳解
java 中 ChannelHandler的用法詳解
前言:
ChannelHandler處理一個I/O event或者攔截一個I/O操作,在它的ChannelPipeline中將其遞交給相鄰的下一個handler。
通過繼承ChannelHandlerAdapter來代替
因為這個接口有許多的方法需要實現(xiàn),你或許希望通過繼承ChannelHandlerAdapter來代替。
context對象
一個ChannelHandler和一個ChannelHandlerContext對象一起被提供。一個ChannelHander通過一個context對象和其所屬的那個ChannelPipeline進行交互。使用context對象,ChannelHandler可以向上或者向下傳遞events,動態(tài)地修改pipeline,或者存儲與handler相關(guān)的信息(使用AttributeKeys)。
狀態(tài)管理
一個ChannelHandler經(jīng)常需要存儲一些狀態(tài)相關(guā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();
}
}
}
...
}
因為handler實例有一個狀態(tài)變量專注于一個連接,你必須為每一個handler實例創(chuàng)建一個新的handler實例,來避免競態(tài)的情況以至于未認證的客戶端可以獲得機密的信息:
// 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
雖然使用成員變量來保存一個handler的狀態(tài)是被推薦的,然而,由于一些原因你或許不想創(chuàng)建很多的handler實例。在這種情況下,你可以使用附在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實例到不同的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注解。
如果一個ChannelHandler被注解為@Sharable,那意味著你可以只創(chuàng)建一個handler實例,并把它添加到一個或多個ChannelPipeline中多次,并不用考慮競態(tài)的情況。
如果這個注解沒有指定,你就只能為每次需要添加到pipeline中的handler,每次創(chuàng)建一個新的實例。因為它有非共享的狀態(tài),比如:成員變量。
如有疑問請留言或者到本站社區(qū)交流討論,感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
相關(guān)文章
Java使用多線程批次查詢大量數(shù)據(jù)(Callable返回數(shù)據(jù))方式
今天給大家分享Java使用多線程批次查詢大量數(shù)據(jù)(Callable返回數(shù)據(jù))方式,多線程有好幾種方式,今天說的方式比較好,實現(xiàn)Callable<> 這種方式能返回查詢的數(shù)據(jù),加上Future異步獲取方式,查詢效率大大加快,感興趣的朋友一起看看吧2023-11-11
SpringBoot整合EasyExcel實現(xiàn)大規(guī)模數(shù)據(jù)的并行導出與壓縮下載
在 Spring Boot 應(yīng)用中,整合 EasyExcel 實現(xiàn)并行導出數(shù)據(jù)并進行 Zip 壓縮下載可以極大地提高數(shù)據(jù)處理效率和用戶體驗,文中通過代碼示例介紹的非常詳細,具有一定的參考價值,需要的朋友可以參考下2024-10-10

