2023-09-13  阅读(3)
原文作者:https://blog.csdn.net/wangwei19871103/category_9681495_2.html 原文地址: https://blog.csdn.net/wangwei19871103/article/details/104123441

ChannelInboundInvoker接口

这个就是入站调用者的接口,也就是说有信息过来了,他可能会触发哪些事件:

202309132158412771.png
具体的都是一些接受消息的事件方法,也就是被动的。

ChannelOutboundInvoker接口

有来的数据,当然有写出去的啦:

202309132158426292.png
具体都是一些发送消息事件方法,基本都是主动的。

ChannelPipeline接口

而我们的管道也是继承上面的接口的,也就是一个主动的调用者:

202309132158436783.png
也就是说所有的进出信息都需要经过管道,所有的处理事件也会经过管道。我们来看看管道自己定义了哪些接口,没截完整,有点长,但是可以看出来基本都是一些增删改查的操作,还有一些出站入站接口的覆盖:

202309132158443434.png

202309132158454505.png
所以可以看出来,管道就是个容器,管理着里面的处理器。

ChannelHandlerContext接口

通道处理器上下文接口,也是个主动的调用者,这个东西其实就是处理器的包装,处理器只要负责处理数据,至于数据是哪里来,又要往哪里去,处理器之间怎么通信,处理器怎么和管道交互,都由处理器上下文来管理,而且管道中其实存放的是处理器上下文,处理器是被包装在里面的,这个后面我们会看到,先来看看这个接口:

202309132158464786.png
他也是实现了上面的出站入站接口,因为要相应管道的操作呀,他还实现了一个AttributeMap接口,这个是给通道设置属性的,后面会讲到。来看看他的接口方法:

202309132158472227.png

除了入站的操作外,还保存了通道,事件执行器,处理器,字节缓冲区分配器,管道,可见他就是跟这些交互的桥梁啊。

AbstractChannelHandlerContext抽象类

实现了ChannelHandlerContext接口,和资源泄露提示的接口ResourceLeakHint

202309132158482628.png
他基本已经把所有的处理器上下文接口都实现了,除了handler()方法,内部还定义了HeadContextTailContext两个上下文,作为基本处理器,具体后面会讲。他没实现handler()方法,具体交给默认实现类实现。HeadContextTailContext的处理器就是他们本身。

DefaultChannelHandlerContext

AbstractChannelHandlerContext默认实现类,实现了handler()方法,就是创建时候传进来的处理器。

    final class DefaultChannelHandlerContext extends AbstractChannelHandlerContext {
    	//保存处理器
        private final ChannelHandler handler;
    
        DefaultChannelHandlerContext(
                DefaultChannelPipeline pipeline, EventExecutor executor, String name, ChannelHandler handler) {
            super(pipeline, executor, name, handler.getClass());
            this.handler = handler;//设置处理器
        }
    
        @Override
        public ChannelHandler handler() {
            return handler;
        }
    }

ChannelHandler接口

这个就是我们的处理器啦,他只是个原始接口,只有处理器的添加和删除事件:

202309132158491829.png

ChannelInboundHandler接口

入站处理器接口,这个就是定义入站处理器要做哪些操作,其实和前面的ChannelInboundInvoker是对应的,只是处理器是负责真正的处理,调用者负责触发某些事件:

2023091321585000610.png

ChannelOutboundHandler接口

出站处理器接口也类似:

2023091321585101611.png

ChannelHandlerAdapter抽象类

他是处理器实现的一个基本骨架,他实现的添加和删除方法都是空的,需要子类覆盖:

2023091321585213012.png

ChannelInboundHandlerAdapter实现类

我们常用的是这个,他继承了ChannelHandlerAdapter,还实现了ChannelInboundHandler接口,所以他就可以处理入站事件啦:

2023091321585350713.png
其实他的所有方法默认都是不触发的,因为有Skip标注,这个我前面有讲过,处理器会匹配相应的处理方法,标注了就不会被匹配到了,也就跳过这个处理器了,也就是默认子类不覆盖方法就是不处理的:

2023091321585457514.png
我们可以看看ChannelInboundHandlerAdapter源码:

    public class ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler {
    
      
        @Skip
        @Override
        public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
            ctx.fireChannelRegistered();
        }
    
       
        @Skip
        @Override
        public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
            ctx.fireChannelUnregistered();
        }
    
      
        @Skip
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            ctx.fireChannelActive();
        }
    
        @Skip
        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            ctx.fireChannelInactive();
        }
    
    
        @Skip
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            ctx.fireChannelRead(msg);
        }
    
    
        @Skip
        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
            ctx.fireChannelReadComplete();
        }
    
    
        @Skip
        @Override
        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
            ctx.fireUserEventTriggered(evt);
        }
    
    
        @Skip
        @Override
        public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
            ctx.fireChannelWritabilityChanged();
        }
    
        @Skip
        @Override
        @SuppressWarnings("deprecation")
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
                throws Exception {
            ctx.fireExceptionCaught(cause);
        }
    }

默认全是跳过的,其实里面的实现ctx.fireXX也是继续传递给下一个处理器处理。

ChannelOutboundHandlerAdapter实现类

当然出站的也类似:

2023091321585544415.png

DefaultChannelPipeline数据的入站出站

首先他是ChannelPipeline接口的实现类,拥有管理通道上下文的能力,同时又实现了出站入站调用者,也就是有能力可以触发那些事件:

2023091321585782716.png
我们先画个大致的图,看看他是怎么管理的:

2023091321585890917.png
如果有出入站事件来了,传播的路径可能是这样的,所有事件都传递下去了:

2023091321590016218.png
当然也可能某个处理器处理完了不传递数据了,比如入站事件入站处理器1处理了,然后就完了,因为他没调用ctx.fireChannelRead(msg);

2023091321590148619.png
当然出如站处理器也可以这样,入站数据传递到入站处理器3,然后直接在入站处理器3这里进行写,然后出站数据传递到出站处理器2里不再传递了,其实一般的写只是写在出站缓冲区中,还并没有写进通道里,这个具体后面会详细讲:

2023091321590221620.png
所以这个入站出站的顺序和操作非常灵活,只要搞明白原理,就觉得这个真的非常强大。今天只是先做个铺垫,没讲什么源码,下一篇就着重讲这个入站出站的过程和原理,还有里面的一些细节,这个也是很重要的,这样你才能设计出强大的处理器链条,才能用更少的处理器组合出强大的功能,才能再出问题的时候知道要怎么解决问题。

好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。


Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文