public interface ChannelHandler
ChannelInboundInvoker
or ChannelOutboundInvoker
operation, and forwards it
to the next handler in a ChannelPipeline
.
ChannelHandler
itself does not provide many methods. To handle a
a ChannelInboundInvoker
or ChannelOutboundInvoker
operation
you need to implement its sub-interfaces. There are many different sub-interfaces
which handles inbound and outbound operations.
But the most useful for developers may be:
ChannelInboundHandlerAdapter
handles and intercepts inbound operationsChannelOutboundHandlerAdapter
handles and intercepts outbound operations
A ChannelHandler
is provided with a ChannelHandlerContext
object. A ChannelHandler
is supposed to interact with the
ChannelPipeline
it belongs to via a context object. Using the
context object, the ChannelHandler
can pass events upstream or
downstream, modify the pipeline dynamically, or store the information
(using AttributeKey
s) which is specific to the handler.
ChannelHandler
often needs to store some stateful information.
The simplest and recommended approach is to use member variables:
public interface Message { // your methods here } public class DataServerHandler extendsBecause the handler instance has a state variable which is dedicated to one connection, you have to create a new handler instance for each new channel to avoid a race condition where a unauthenticated client can get the confidential information:SimpleChannelInboundHandler
<Message> { private boolean loggedIn;@Override
public void channelRead0(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(); } } } ... }
// Create a new handler instance per channel. // SeeChannelInitializer.initChannel(Channel)
. public class DataServerInitializer extendsChannelInitializer
<Channel
> {@Override
public void initChannel(Channel
channel) { channel.pipeline().addLast("handler", new DataServerHandler()); } }
AttributeKey
AttributeKey
s which is provided by
ChannelHandlerContext
:
public interface Message { // your methods here }Now that the state of the handler isattached to the@Sharable
public class DataServerHandler extendsSimpleChannelInboundHandler
<Message> { private finalAttributeKey
<Boolean
> auth =AttributeKey.valueOf("auth")
;@Override
public void channelRead(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(); } } } ... }
ChannelHandlerContext
, you can add the
same handler instance to different pipelines:
public class DataServerInitializer extendsChannelInitializer
<Channel
> { private static final DataServerHandler SHARED = new DataServerHandler();@Override
public void initChannel(Channel
channel) { channel.pipeline().addLast("handler", SHARED); } }
@Sharable
annotation
In the example above which used an AttributeKey
,
you might have noticed the @Sharable
annotation.
If a ChannelHandler
is annotated with the @Sharable
annotation, it means you can create an instance of the handler just once and
add it to one or more ChannelPipeline
s multiple times without
a race condition.
If this annotation is not specified, you have to create a new handler instance every time you add it to a pipeline because it has unshared state such as member variables.
This annotation is provided for documentation purpose, just like the JCIP annotations.
Please refer to the ChannelHandler
, and
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.
Modifier and Type | Interface and Description |
---|---|
static interface |
ChannelHandler.Sharable
Indicates that the same instance of the annotated
ChannelHandler
can be added to one or more ChannelPipeline s multiple times
without a race condition. |
Modifier and Type | Method and Description |
---|---|
void |
exceptionCaught(ChannelHandlerContext ctx,
Throwable cause)
Deprecated.
is part of
ChannelInboundHandler |
void |
handlerAdded(ChannelHandlerContext ctx)
Gets called after the
ChannelHandler was added to the actual context and it's ready to handle events. |
void |
handlerRemoved(ChannelHandlerContext ctx)
Gets called after the
ChannelHandler was removed from the actual context and it doesn't handle events
anymore. |
void handlerAdded(ChannelHandlerContext ctx) throws Exception
ChannelHandler
was added to the actual context and it's ready to handle events.Exception
void handlerRemoved(ChannelHandlerContext ctx) throws Exception
ChannelHandler
was removed from the actual context and it doesn't handle events
anymore.Exception
@Deprecated void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
ChannelInboundHandler
Throwable
was thrown.Exception
Copyright © 2008–2018 The Netty Project. All rights reserved.