Add ChannelHandlerContext.invoker()
Motivation:
Being able to access the invoker() is useful when adding additional
handlers that should be running in the same thread. Since an application
may be using a threading model unsupported by the default invoker, they
can specify their own. Because of that, in a handler that auto-adds
other handlers:
// This is a good pattern
ctx.pipeline().addBefore(ctx.invoker(), ctx.name(), null, newHandler);
// This will generally work, but prevents using custom invoker.
ctx.pipeline().addBefore(ctx.executor(), ctx.name(), null, newHandler);
That's why I believe in commit 110745b0
, for the now-defunct 5.0 branch,
when ChannelHandlerAppender was added the invoker() method was also
necessary.
There is a side-benefit to exposing the invoker: in certain advanced
use-cases using the invoker for a particular handler is useful. Using
the invoker you are able to invoke a _particular_ handler, from possibly
a different thread yet still using standard exception processing.
ChannelHandlerContext does part of that, but is unwieldy when trying to
invoke a particular handler because it invokes the prev or next handler,
not the one the context is for. A workaround is to use the next or prev
context (respectively), but this breaks when the pipeline changes.
This came up during writing the Http2MultiplexCodec which uses a
separate child channel for each http/2 stream and wants to send messages
from the child channel directly to the Http2MultiplexCodec handler that
created it.
Modifications:
Add the invoker() method to ChannelHandlerContext. It was already being
implemented by AbstractChannelHandlerContext. The two other
implementations of ChannelHandlerContext needed minor tweaks.
Result:
Access to the invoker used for a particular handler, for either reusing
for other handlers or for advanced use-cases. Fixes #4738
This commit is contained in:
parent
d1ef33b8f4
commit
6dbb610f5b
@ -20,9 +20,11 @@ import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelHandlerInvoker;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.ChannelProgressivePromise;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.channel.EventLoop;
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.util.Attribute;
|
||||
import io.netty.util.AttributeKey;
|
||||
@ -33,7 +35,7 @@ import java.net.SocketAddress;
|
||||
|
||||
public abstract class EmbeddedChannelWriteReleaseHandlerContext implements ChannelHandlerContext {
|
||||
private static final String HANDLER_NAME = "microbench-delegator-ctx";
|
||||
private final EventExecutor executor;
|
||||
private final EventLoop eventLoop;
|
||||
private final Channel channel;
|
||||
private final ByteBufAllocator alloc;
|
||||
private final ChannelHandler handler;
|
||||
@ -48,7 +50,7 @@ public abstract class EmbeddedChannelWriteReleaseHandlerContext implements Chann
|
||||
this.alloc = checkNotNull(alloc, "alloc");
|
||||
this.channel = checkNotNull(channel, "channel");
|
||||
this.handler = checkNotNull(handler, "handler");
|
||||
this.executor = checkNotNull(channel.eventLoop(), "executor");
|
||||
this.eventLoop = checkNotNull(channel.eventLoop(), "eventLoop");
|
||||
}
|
||||
|
||||
protected abstract void handleException(Throwable t);
|
||||
@ -70,7 +72,12 @@ public abstract class EmbeddedChannelWriteReleaseHandlerContext implements Chann
|
||||
|
||||
@Override
|
||||
public EventExecutor executor() {
|
||||
return executor;
|
||||
return eventLoop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelHandlerInvoker invoker() {
|
||||
return eventLoop.asInvoker();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -82,6 +82,7 @@ abstract class AbstractChannelHandlerContext implements ChannelHandlerContext, R
|
||||
return invoker().executor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelHandlerInvoker invoker() {
|
||||
if (invoker == null) {
|
||||
return channel().unsafe().invoker();
|
||||
|
@ -136,6 +136,14 @@ public interface ChannelHandlerContext extends AttributeMap {
|
||||
*/
|
||||
EventExecutor executor();
|
||||
|
||||
/**
|
||||
* Returns the {@link ChannelHandlerInvoker} which is used to trigger an event for the associated
|
||||
* {@link ChannelHandler}. Note that the methods in {@link ChannelHandlerInvoker} are not intended to be called
|
||||
* by a user. Use this method only to obtain the reference to the {@link ChannelHandlerInvoker}
|
||||
* (and not calling its methods) unless you know what you are doing.
|
||||
*/
|
||||
ChannelHandlerInvoker invoker();
|
||||
|
||||
/**
|
||||
* The unique name of the {@link ChannelHandlerContext}.The name was used when then {@link ChannelHandler}
|
||||
* was added to the {@link ChannelPipeline}. This name can also be used to access the registered
|
||||
|
@ -372,6 +372,11 @@ public class CombinedChannelDuplexHandler<I extends ChannelInboundHandler, O ext
|
||||
return ctx.executor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelHandlerInvoker invoker() {
|
||||
return ctx.invoker();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return ctx.name();
|
||||
|
Loading…
Reference in New Issue
Block a user