Nettyソース分析(十二)チャネルとチャネルハンドラー及びチャネルハンドラーContextの関係分析
18383 ワード
まだ前のinitコードのエントリで、前節ではChannelOptionとAttributeKeyを紹介しましたが、今回はChannelとChannelHandlerおよびChannelHandlerContextの関係分析についてお話しします.
まずChannelInitializerからdocを見てみましょう
void init(Channel channel) throws Exception {
final Map, Object> options = options0();
synchronized (options) {
setChannelOptions(channel, options, logger);
}
final Map, Object> attrs = attrs0();
synchronized (attrs) {
for (Entry, Object> e: attrs.entrySet()) {
@SuppressWarnings("unchecked")
AttributeKey
まずChannelInitializerからdocを見てみましょう
/**
* A special {@link ChannelInboundHandler} which offers an easy way to initialize a {@link Channel} once it was
* registered to its {@link EventLoop}.
* ChannelInboundHandler, Channel, EventLoop 。
* Implementations are most often used in the context of {@link Bootstrap#handler(ChannelHandler)} ,
* {@link ServerBootstrap#handler(ChannelHandler)} and {@link ServerBootstrap#childHandler(ChannelHandler)} to
* setup the {@link ChannelPipeline} of a {@link Channel}.
* Bootstrap#handler(ChannelHandler)、ServerBootstrap#handler(ChannelHandler)、
* ServerBootstrap#childHandler(ChannelHandler) Channel ChannelPipeline
*
* :
* public class MyChannelInitializer extends {@link ChannelInitializer} {
* public void initChannel({@link Channel} channel) {
* channel.pipeline().addLast("myHandler", new MyHandler());
* }
* }
*
* {@link ServerBootstrap} bootstrap = ...;
* ...
* bootstrap.childHandler(new MyChannelInitializer());
* ...
*
* Be aware that this class is marked as {@link Sharable} and so the implementation must be safe to be re-used.
*このクラスはSharableと されているので、 にはスレッドが である があります.
* @param A sub-type of {@link Channel}
*/
@Sharable
public abstract class ChannelInitializer extends ChannelInboundHandlerAdapter {
}
プログラム び しp.addLast(new ChannelInitializer()…というようにChannelInitializerをChannelPipelineに れるのですが、ChannelPipeline.addLast()の はどうなっているのでしょうか. /**
* Inserts {@link ChannelHandler}s at the last position of this pipeline.
* pipeline ChannelHandler
* @param handlers the handlers to insert last
*/
ChannelPipeline addLast(ChannelHandler... handlers);
ChannelPipelineの クラスを するには、 の に います.public class DefaultChannelPipeline implements ChannelPipeline {
...
@Override
public final ChannelPipeline addLast(ChannelHandler... handlers) {
return addLast(null, handlers);
}
...
addLast(null,handlers)が び され、 のパラメータはnullです. executor null
public final ChannelPipeline addLast(EventExecutorGroup executor, ChannelHandler... handlers) {
if (handlers == null) {
throw new NullPointerException("handlers");
}
// , addLast(executor, null, h) , null
for (ChannelHandler h: handlers) {
if (h == null) {
break;
}
addLast(executor, null, h);
}
return this;
}
な に ります.groupはnull、nameはnullです. public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;// AbstractChannelHandlerContext
synchronized (this) {
checkMultiplicity(handler);
newCtx = newContext(group, filterName(name, handler), handler);
addLast0(newCtx);
// If the registered is false it means that the channel was not registered on an eventloop yet.
// In this case we add the context to the pipeline and add a task that will call
// ChannelHandler.handlerAdded(...) once the channel is registered.
if (!registered) {
newCtx.setAddPending();
callHandlerCallbackLater(newCtx, true);
return this;
}
EventExecutor executor = newCtx.executor();
if (!executor.inEventLoop()) {
newCtx.setAddPending();
executor.execute(new Runnable() {
@Override
public void run() {
callHandlerAdded0(newCtx);
}
});
return this;
}
}
callHandlerAdded0(newCtx);
return this;
}
AbstractChannelHandlerContextについては、AbstractChannelHandlerContextのdocがどのようなものかを てみましょう.abstract class AbstractChannelHandlerContext extends DefaultAttributeMap
implements ChannelHandlerContext, ResourceLeakHint {
のインターフェイスに りますChannelHandlerContext:
/**
* Enables a {@link ChannelHandler} to interact with its {@link ChannelPipeline}
* and other handlers. Among other things a handler can notify the next {@link ChannelHandler} in the
* {@link ChannelPipeline} as well as modify the {@link ChannelPipeline} it belongs to dynamically.
* ChannelHandler ChannelPipeline , ChannelPipeline ChannelHandler,
* ChannelPipeline
* Notify
*
* You can notify the closest handler in the same {@link ChannelPipeline} by calling one of the various methods
* provided here.
* ChannelPipeline handler
* Please refer to {@link ChannelPipeline} to understand how an event flows.
* ChannelPipeline 。
* Modifying a pipeline
* pipeline
* You can get the {@link ChannelPipeline} your handler belongs to by calling
* {@link #pipeline()}. A non-trivial application could insert, remove, or
* replace handlers in the pipeline dynamically at runtime.
* pipeline() ChannelPipeline, pipeline , 。
* Retrieving for later use
*
* You can keep the {@link ChannelHandlerContext} for later use, such as
* triggering an event outside the handler methods, even from a different thread.
* ChannelHandlerContext , handler , 。
*
* public class MyHandler extends {@link ChannelDuplexHandler} {
*
* private {@link ChannelHandlerContext} ctx;
*
* public void beforeAdd({@link ChannelHandlerContext} ctx) {
* this.ctx = ctx;</b>// ChannelHandlerContext
* }
*
* public void login(String username, password) {
* ctx.write(new LoginMessage(username, password));//
* }
* ...
* }
*
*
* Storing stateful information
*ステータス の
* {@link #attr(AttributeKey)} allow you to
* store and access stateful information that is related with a handler and its
* context. Please refer to {@link ChannelHandler} to learn various recommended
* ways to manage stateful information.
*AttributeKeyでは、 するhandlerとそのコンテキストのステータス を できます.ChannelHandlerを して、ステータス を する を できます.
* A handler can have more than one context
*1つのhandlerには のコンテキストがあります.
* Please note that a {@link ChannelHandler} instance can be added to more than
* one {@link ChannelPipeline}. It means a single {@link ChannelHandler}
* instance can have more than one {@link ChannelHandlerContext} and therefore
* the single instance can be invoked with different
* {@link ChannelHandlerContext}s if it is added to one or more
* {@link ChannelPipeline}s more than once.
*1つのChannelHandlerは、1つのChannelPipelineに することができ、1つの のChannelHandlerインスタンスが あることを する
*ChannelHandlerContextは、 のChannelHandlerContextによって のインスタンスを び すことができ、ChannelHandlerインスタンスが された に び すことができる.
*
* For example, the following handler will have as many independent {@link AttributeKey}s
* as how many times it is added to pipelines, regardless if it is added to the
* same pipeline multiple times or added to different pipelines multiple times:
*
* public class FactorialHandler extends {@link ChannelInboundHandlerAdapter} {
*
* private final {@link AttributeKey}<{@link Integer}> counter = {@link AttributeKey}.valueOf("counter");
*
* // This handler will receive a sequence of increasing integers starting
* // from 1.
* {@code @Override}
* public void channelRead({@link ChannelHandlerContext} ctx, Object msg) {
* Integer a = ctx.attr(counter).get();
*
* if (a == null) {
* a = 1;
* }
*
* attr.set(a * (Integer) msg);
* }
* }
*
* // Different context objects are given to "f1", "f2", "f3", and "f4" even if
* // they refer to the same handler instance. Because the FactorialHandler
* // stores its state in a context object (using an {@link AttributeKey}), the factorial is
* // calculated correctly 4 times once the two pipelines (p1 and p2) are active.
* "f1", "f2", "f3", and "f4" , , FactorialHandler
* ( AttributeKey), factorial ,factorial 2 pipelines (p1 p2) 。
* FactorialHandler fh = new FactorialHandler();
*
* {@link ChannelPipeline} p1 = {@link Channels}.pipeline();
* p1.addLast("f1", fh);
* p1.addLast("f2", fh);
*
* {@link ChannelPipeline} p2 = {@link Channels}.pipeline();
* p2.addLast("f3", fh);
* p2.addLast("f4", fh);
*
*
* Additional resources worth reading
*
* Please refer to the {@link ChannelHandler}, and
* {@link ChannelPipeline} to find out more about inbound and outbound operations,
* what fundamental differences they have, how they flow in a pipeline, and how to handle
* the operation in your application.
*ChannelHandlerとChannelPipelineを して、アウトスタックとインスタックの 、 らの の も な い、pipelineでどのように れているのか、アプリケーションでどのように されているのかを してください.
*/
public interface ChannelHandlerContext extends AttributeMap, ChannelInboundInvoker, ChannelOutboundInvoker {