Netty源码—5.Pipeline和Handler二

大纲

1.Pipeline和Handler的作用和构成

2.ChannelHandler的分类

3.几个特殊的ChannelHandler

4.ChannelHandler的生命周期

5.ChannelPipeline的事件处理

6.关于ChannelPipeline的问题整理

7.ChannelPipeline主要包括三部分内容

8.ChannelPipeline的初始化

9.ChannelPipeline添加ChannelHandler

10.ChannelPipeline删除ChannelHandler

11.Inbound事件的传播

12.Outbound事件的传播

13.ChannelPipeline中异常的传播

14.ChannelPipeline总结

10.ChannelPipeline删除ChannelHandler

Netty最大的特征之一就是ChannelHandler是可插拔的,可以动态编织ChannelPipeline。比如在客户端首次连接服务端时,需要进行权限认证,认证通过后就可以不用再认证了。下面的AuthHandler便实现了只对第一个传来的数据包进行认证校验。如果通过验证则删除此AuthHandler,这样后续传来的数据包便不会再校验了。

public class AuthHandler extends SimpleChannelInboundHandler<ByteBuf> {
    ...
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf data) throw Exception {
        if (verify(data)) {
            ctx.pipeline().remove(this);     
        } else {
            ctx.close();
        }
    }
}

DefaultChannelPipeline的remove()方法如下:

public class DefaultChannelPipeline implements ChannelPipeline {
    ...
    @Override
    public final ChannelPipeline remove(ChannelHandler handler) {
        remove(getContextOrDie(handler));
        return this;
    }
    
    private AbstractChannelHandlerContext getContextOrDie(ChannelHandler handler) {
        AbstractChannelHandlerContext ctx = (AbstractChannelHandlerContext) context(handler);
        if (ctx == null) {
            throw new NoSuchElementException(handler.getClass().getName());
        } else {
            return ctx;
        }
    }
    
    @Override
    public final ChannelHandlerContext context(ChannelHandler handler) {
        ...
        AbstractChannelHandlerContext ctx = head.next;
        //遍历双向链表
        for (;;) {
            ...
            if (ctx.handler() == handler) return ctx;
            ctx = ctx.next;
        }
    }
    
    private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) { 
        //Pipeline中的head和tail结点不能被删除
        assert ctx != head && ctx != tail;
        synchronized (this) {
            //调整链表指针并删除
            remove0(ctx);
            ...
        }
        //回调用户在这个要删除的ChannelHandler实现的handlerRemoved()方法
        callHandlerRemoved0(ctx);
        return ctx;
    }

    private static void remove0(AbstractChannelHandlerContext ctx) {
        AbstractChannelHandlerContext prev = ctx.prev;
        AbstractChannelHandlerContext next = ctx.next;
        prev.next = next;
        next.prev = prev;
    }
    
    private void callHandlerRemoved0(final AbstractChannelHandlerContext ctx) {
        ...
        ctx.handler().handlerRemoved(ctx);
        ...
    }
    ...
}

ChannelPipeline删除ChannelHandler的步骤:

一.遍历双向链表,根据ChannelHandler找到对应的ChannelHandlerContext结点。

二.通过调整ChannelPipeline中双向链表的指针来删除对应的ChannelHandlerContext结点。

三.回调用户在这个要删除的ChannelHandler实现的handlerRemoved()方法,比如进行资源清理。

11.Inbound事件的传播

(1)Unsafe的介绍

(2)Unsafe的继承结构

(3)Unsafe的分类

(4)ChannelPipeline中Inbound事件传播

(5)ChannelPipeline中的头结点和尾结点

(6)Inbound事件的传播总结

(1)Unsafe的介绍

Unsafe和ChannelPipeline密切相关,ChannelPipeline中有关IO的操作最终都会落地到Unsafe的。Unsafe是不安全的意思,即不要在应用程序里直接使用Unsafe及它的衍生类对象。Unsafe是在Channel中定义的,是属于Channel的内部类。Unsafe中的接口操作都和JDK底层相关,包括:分配内存、Socket四元组信息、注册事件循环、绑定端口、Socket的连接和关闭、Socket的读写。

//A nexus to a network socket or a component which is capable of I/O operations such as read, write, connect, and bind.
public interface Channel extends AttributeMap, ChannelOutboundInvoker, Comparable<Channel> {
    //Returns the globally unique identifier of this Channel.
    ChannelId id();
    
    //Return the EventLoop this Channel was registered to.
    EventLoop eventLoop();

    //Returns the parent of this channel.
    Channel parent();

    //Returns the configuration of this channel.
    ChannelConfig config();

    //Returns true if the Channel is open and may get active later
    boolean isOpen();

    //Returns true if the Channel is registered with an EventLoop.
    boolean isRegistered();

    //Return true if the Channel is active and so connected.
    boolean isActive();

    //Return the ChannelMetadata of the Channel which describe the nature of the Channel.
    ChannelMetadata metadata();

    //Returns the local address where this channel is bound to.  
    //The returned SocketAddress is supposed to be down-cast into more concrete type such as InetSocketAddress to retrieve the detailed information. 
    SocketAddress localAddress();

    //Returns the remote address where this channel is connected to.  
    //The returned SocketAddress is supposed to be down-cast into more concrete type such as InetSocketAddress to retrieve the detailed information.
    SocketAddress remoteAddress();

    //Returns the ChannelFuture which will be notified when this channel is closed.  
    //This method always returns the same future instance.
    ChannelFuture closeFuture();

    //Returns true if and only if the I/O thread will perform the requested write operation immediately.  
    //Any write requests made when this method returns false are queued until the I/O thread is ready to process the queued write requests.
    boolean isWritable();

    //Get how many bytes can be written until #isWritable() returns false.
    //This quantity will always be non-negative. If #isWritable() is false then 0.
    long bytesBeforeUnwritable();

    //Get how many bytes must be drained from underlying buffers until #isWritable() returns true.
    //This quantity will always be non-negative. If #isWritable() is true then 0.
    long bytesBeforeWritable();

    //Returns an <em>internal-use-only</em> object that provides unsafe operations.
    Unsafe unsafe();

    //Return the assigned ChannelPipeline.
    ChannelPipeline pipeline();

    //Return the assigned ByteBufAllocator which will be used to allocate ByteBufs.
    ByteBufAllocator alloc();

    @Override
    Channel read();

    @Override
    Channel flush();

    //Unsafe operations that should never be called from user-code. 
    //These methods are only provided to implement the actual transport, and must be invoked from an I/O thread except for the following methods:
    //#invoker()
    //#localAddress()
    //#remoteAddress()
    //#closeForcibly()
    //#register(EventLoop, ChannelPromise)
    //#deregister(ChannelPromise)
    //#voidPromise()
    interface Unsafe {
        //Return the assigned RecvByteBufAllocator.Handle which will be used to allocate ByteBuf's when receiving data.
        RecvByteBufAllocator.Handle recvBufAllocHandle();

        //Return the SocketAddress to which is bound local or null if none.
        SocketAddress localAddress();

        //Return the SocketAddress to which is bound remote or null if none is bound yet.
        SocketAddress remoteAddress();

        //Register the Channel of the ChannelPromise and notify the ChannelFuture once the registration was complete.
        void register(EventLoop eventLoop, ChannelPromise promise);

        //Bind the SocketAddress to the Channel of the ChannelPromise and notify it once its done.
        void bind(SocketAddress localAddress, ChannelPromise promise);

        //Connect the Channel of the given ChannelFuture with the given remote SocketAddress.
        //If a specific local SocketAddress should be used it need to be given as argument. Otherwise just pass null to it.
        //he ChannelPromise will get notified once the connect operation was complete.
        void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise);

        //Disconnect the Channel of the ChannelFuture and notify the ChannelPromise once the operation was complete.
        void disconnect(ChannelPromise promise);

        //Close the Channel of the ChannelPromise and notify the ChannelPromise once the operation was complete.
        
下载方式:https://pan.quark.cn/s/c9b9b647468b ### 初级JSP程序设计教程核心内容解析#### 一、JSP基础概述JSP(JavaServer Pages)是由Sun Microsystems公司创建的一种动态网页技术规范,主要应用于构建动态网站及Web应用。JSP技术使得开发者能够将动态数据与静态HTML文档整合,从而实现网页内容的灵活性可变性。##### JSP的显著特性:1. **动态与静态内容的分离**:JSP技术支持将动态数据(例如数据库查询结果、实时时间等)嵌入到静态HTML文档中。这种设计方法增强了网页的适应性可维护性。2. **易用性**:开发者可以利用常规的HTML编辑工具来编写静态部分,并通过简化的标签技术将动态内容集成到页面中。3. **跨平台兼容性**:基于Java平台的JSP具有优良的跨操作系统运行能力,能够在多种不同的系统环境中稳定工作。4. **强大的后台支持**:JSP能够通过JavaBean组件访问后端数据库及其他资源,以实现复杂的数据处理逻辑。5. **执行效率高**:JSP页面在初次被请求时会被转换为Servlet,随后的请求可以直接执行编译后的Servlet代码,从而提升了服务响应的效率。#### 、JSP指令的运用JSP指令用于设定整个JSP页面的行为规范。这些指令通常放置在页面的顶部,向JSP容器提供处理页面的相关指导信息。##### 主要的指令类型:1. **Page指令**: - **语法结构**:`<%@ page attribute="value" %>` - **功能**:定义整个JSP页面的运行特性,如设定页面编码格式、错误处理机制等。 - **实例**: ...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值