• 02handler


    第一部分handler
    pipeline是一根管道,数据通过这根管道,首先流向编解码的handler,然后在流向我们自定义的handler中

    1.handler是基于pipeline的
    例如我们需要处理 HTTP 数据, 那么就可以在 pipeline 前添加一个 Http 的编解码的 Handler,
    然后接着添加我们自己的业务逻辑的 handler,

    2.也就是你要处理什么样的请求,tcp,http,或者udp的时候,
    需要在pipeline前添加一个编解码的Handler,
    然后在添加我们自己的handler

    这样网络上的数据流就向通过一个管道一样, 从不同的 handler 中流过并进行编解码, 最终在到达我们自定义的 handler 中.

    .handler(new ChannelInitializer<SocketChannel>() {
    @Override
    public void initChannel(SocketChannel ch) throws Exception {
    ChannelPipeline p = ch.pipeline();
    if (sslCtx != null) {
    p.addLast(sslCtx.newHandler(ch.alloc(), HOST, PORT));
    }
    //p.addLast(new LoggingHandler(LogLevel.INFO));
    p.addLast(new EchoClientHandler());
    }
    });

    handler方法,参数是ChannelHandler,我们传入进去的是ChannelInitializer
    ChannelInitializer是 ChannelHandlerAdapter的子类

    public abstract class ChannelHandlerAdapter implements ChannelHandler

    public B handler(ChannelHandler handler) {
    if (handler == null) {
    throw new NullPointerException("handler");
    }
    this.handler = handler;
    return (B) this;
    }

    2.ChannelInitializer是一个抽象类,
    里面有一个initChannel方法,接收Channel的参数
    public abstract class ChannelInitializer<C extends Channel> extends ChannelInboundHandlerAdapter {

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(ChannelInitializer.class);
    // We use a ConcurrentMap as a ChannelInitializer is usually shared between all Channels in a Bootstrap /
    // ServerBootstrap. This way we can reduce the memory usage compared to use Attributes.
    private final ConcurrentMap<ChannelHandlerContext, Boolean> initMap = PlatformDependent.newConcurrentHashMap();

    /**
    * This method will be called once the {@link Channel} was registered. After the method returns this instance
    * will be removed from the {@link ChannelPipeline} of the {@link Channel}.
    *
    * @param ch the {@link Channel} which was registered.
    * @throws Exception is thrown if an error occurs. In that case it will be handled by
    * {@link #exceptionCaught(ChannelHandlerContext, Throwable)} which will by default close
    * the {@link Channel}.
    */
    protected abstract void initChannel(C ch) throws Exception;

    @Override
    @SuppressWarnings("unchecked")
    public final void channelRegistered(ChannelHandlerContext ctx) throws Exception {
    // Normally this method will never be called as handlerAdded(...) should call initChannel(...) and remove
    // the handler.
    if (initChannel(ctx)) {
    // we called initChannel(...) so we need to call now pipeline.fireChannelRegistered() to ensure we not
    // miss an event.
    ctx.pipeline().fireChannelRegistered();
    } else {
    // Called initChannel(...) before which is the expected behavior, so just forward the event.
    ctx.fireChannelRegistered();
    }
    }

    }

    ChannelInitializer 是一个抽象类, 它有一个抽象的方法 initChannel,
    我们正是实现了这个方法, 并在这个方法中添加的自定义的 handler 的.
    那么 initChannel 是哪里被调用的呢? 答案是 ChannelInitializer.channelRegistered 方法中.

    3.我们来关注一下 channelRegistered 方法. 从上面的源码中, 我们可以看到, 在 channelRegistered 方法中,
    会调用 initChannel 方法, 将自定义的 handler 添加到 ChannelPipeline 中,
    然后调用 ctx.pipeline().remove(this) 将自己从 ChannelPipeline 中删除.
    上面的分析过程, 可以用如下图片展示:
    一开始, ChannelPipeline 中只有三个 handler, head, tail 和我们添加的 ChannelInitializer.

    在 channelRegistered 方法会调用 initChannel方法, 参数是 ChannelHandlerContext

    private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
    if (initMap.putIfAbsent(ctx, Boolean.TRUE) == null) { // Guard against re-entrance.
    try {
    initChannel((C) ctx.channel());
    } catch (Throwable cause) {
    // Explicitly call exceptionCaught(...) as we removed the handler before calling initChannel(...).
    // We do so to prevent multiple calls to initChannel(...).
    exceptionCaught(ctx, cause);
    } finally {
    remove(ctx);
    }
    return true;
    }
    return false;
    }

    initChannel((C) ctx.channel())这个方法就是上面那个抽象的方法,需要我们自己去实现

    romove(ctx) 调用 ctx.pipeline().remove(this) 将自己从 ChannelPipeline 中删除.

    private void remove(ChannelHandlerContext ctx) {
    try {
    ChannelPipeline pipeline = ctx.pipeline();
    if (pipeline.context(this) != null) {
    pipeline.remove(this);
    }
    } finally {
    initMap.remove(ctx);
    }
    }

    4.channelPipeline有哪些handler
    一开始, ChannelPipeline 中只有三个 handler, head, tail 和我们添加的 ChannelInitializer.
    head---》ChannelInitializer---》tail

    接着 initChannel 方法调用后, 添加了自定义的 handler:
    p.addLast(new EchoClientHandler());

    head---》ChannelInitializer---》 EchoClientHandler ----》tail

    最后将 ChannelInitializer 删除:
    pipeline.remove(this);
    head---》 EchoClientHandler ----》tail

    分析到这里, 我们已经简单了解了自定义的 handler 是如何添加到 ChannelPipeline 中的,
    不过限于主题与篇幅的原因, 我没有在这里详细展开 ChannelPipeline 的底层机制,
    我打算在下一篇 Netty 源码分析之 二 贯穿Netty 的大动脉 ── ChannelPipeline 中对这个问题进行深入的探讨.

  • 相关阅读:
    Junit单元测试
    win7的6个网络命令
    WOJ1024 (POJ1985+POJ2631) Exploration 树/BFS
    WOJ1022 Competition of Programming 贪心 WOJ1023 Division dp
    woj1019 Curriculum Schedule 输入输出 woj1020 Adjacent Difference 排序
    woj1018(HDU4384)KING KONG 循环群
    woj1016 cherry blossom woj1017 Billiard ball 几何
    woj1013 Barcelet 字符串 woj1014 Doraemon's Flashlight 几何
    woj1012 Thingk and Count DP好题
    woj1010 alternate sum 数学 woj1011 Finding Teamates 数学
  • 原文地址:https://www.cnblogs.com/handsome1013/p/10002839.html
Copyright © 2020-2023  润新知