(一)成員變量
public class DataServerHandler extends SimpleChannelHandler {
private boolean loggedIn;
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
...
}
}
- 如果只是想在當前連接內共享數據,那麼需要針對不同的Channel創建不同的ChannelHandler實例,避免共享範圍擴大至所有連接。
public class DataServerPipelineFactory implements ChannelPipelineFactory {
private static final DataServerHandler SHARED = new DataServerHandler();
public ChannelPipeline getPipeline() {
return Channels.pipeline(SHARED);
}
}
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() {
ChannelPipeline pipeline = pipeline();
pipeline.addLast("handler", new TestHandler());
return pipeline;
}
});
(二)ChannelHandlerContext
- ChannelHandlerContext是在Pipline註冊ChannelHandler的時候和其綁定的,因此一個被多次註冊(無論是否是同一個Pipline)的ChannelHandler會同時擁有多個ChannelHandlerContext。
- 對於ChannelHandlerContext一個常見的誤解是以爲其可以在同一個Pipline的各個Handler之間傳遞數據。如果真要這樣做,應該使用MessageEvent或者ChannelLocal。
@Sharable
public class DataServerHandler extends SimpleChannelHandler {
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
Channel ch = e.getChannel();
Object o = e.getMessage();
if (o instanceof LoginMessage) {
authenticate((LoginMessage) o);
ctx.setAttachment(true);
}
}
}
- @Sharable註解只是起到一個標示的作用,說明一個該ChannelHandler實例可以被多次註冊到一個或者多個Pipline中,而且不會導致不同的Channel共享數據出現競爭條件。
- 基於ChannelHandlerContext同ChannelHandler的綁定時機和機制,很容易理解在本例中是怎麼保證@Sharable的。
(三)Channel
- 該方法類似ChannelLocal,只是共享數據是直接存儲在Channel實例中的。
@Sharable
public class TestHandler extends SimpleChannelHandler {
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent event) throws Exception {
ctx.getChannel().setAttachment(true);
event.getChannel().setAttachment(true);
}
}
- 很明顯,本例中的ChannelLocal也是符合@Sharable要求的。
(四)ChannelLocal
- 如果想在當前連接的其他ChannelHandler或者外部Handler中共享數據,則可以使用ChannelLocal。其設計思想類似於JDK中的ThreadLocal,其內部是一個Channel做Key,共享數據做Value的結構。
public final class DataServerState {
public static final ChannelLocal<Boolean> loggedIn = new ChannelLocal<>() {
protected Boolean initialValue(Channel channel) {
return false;
}
}
}
@Sharable
public class DataServerHandler extends SimpleChannelHandler {
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
Channel ch = e.getChannel();
Object o = e.getMessage();
if (o instanceof LoginMessage) {
authenticate((LoginMessage) o);
DataServerState.loggedIn.set(ch, true);
}
}
}
- 很明顯,本例中的ChannelLocal也是符合@Sharable要求的。