责任链设计模式实战系列(六)

该文深入讲解了Netty中的Pepeline设计,展示了如何通过ChannelPipeline和ChannelHandler实现责任链模式。文中提供了简化后的代码示例,包括添加处理器、触发事件处理等关键操作,以帮助读者理解和应用这一设计思想。
摘要由CSDN通过智能技术生成

前言

  1. 这个系列主要讲优秀的开源框架对于责任链这个设计模式的运用,对于好的设计,我们关键是学习他的思想并运用在我们的编码中。

  2. 这个系列的所有代码都是我根据源码提炼之后的代码,不依赖原项目或框架,可以直接跑。

  3. 我不会讲每个具体是如何实现的,如果你觉得光看代码比较吃力,那么可以将代码复制下来,自己多运行几遍,我相信你一定能掌握。

  4. 欢迎访问我的个人网站,里面有超多开源组件和项目,另外还有付费项目和博客,地址:https://openbytecode.com/

  5. 前五个小节主要介绍了 Tomcat 的 Filter 设计、SpringMVC 的 Interceptor 设计、 Spring 中 AOP 的设计、Mybatis 的 Plugin 设计、Dubbo 的 Filter 设计,本小节主要讲 Netty 的 Pepeline 设计。

  6. 本系列 Github 地址:https://github.com/lijunping365/Open-Design

Netty 之 Pepeline

public interface ChannelPipeline {

    /**
     * Inserts a {@link io.netty.channel.ChannelHandler} at the first position of this pipeline.
     *
     * @param name     the name of the handler to insert first
     * @param handler  the handler to insert first
     *
     * @throws IllegalArgumentException
     *         if there's an entry with the same name already in the pipeline
     * @throws NullPointerException
     *         if the specified handler is {@code null}
     */
    ChannelPipeline addFirst(String name, ChannelHandler handler);

    /**
     * Appends a {@link ChannelHandler} at the last position of this pipeline.
     *
     * @param name     the name of the handler to append
     * @param handler  the handler to append
     *
     * @throws IllegalArgumentException
     *         if there's an entry with the same name already in the pipeline
     * @throws NullPointerException
     *         if the specified handler is {@code null}
     */
    ChannelPipeline addLast(String name, ChannelHandler handler);

    /**
     * A {@link io.netty.channel.Channel} received a message.
     *
     * This will result in having the {@link ChannelInboundHandler#channelRead(io.netty.channel.ChannelHandlerContext, Object)}
     * method  called of the next {@link ChannelInboundHandler} contained in the  {@link io.netty.channel.ChannelPipeline} of the
     * {@link io.netty.channel.Channel}.
     */
    void fireChannelRead(Object msg);

    /**
     * Triggers an {@link ChannelInboundHandler#channelReadComplete(io.netty.channel.ChannelHandlerContext)}
     * event to the next {@link ChannelInboundHandler} in the {@link io.netty.channel.ChannelPipeline}.
     */
    void fireChannelReadComplete();

    /**
     * A {@link io.netty.channel.Channel} received an {@link Throwable} in one of its inbound operations.
     *
     * This will result in having the  {@link ChannelInboundHandler#exceptionCaught(io.netty.channel.ChannelHandlerContext, Throwable)}
     * method  called of the next  {@link ChannelInboundHandler} contained in the  {@link io.netty.channel.ChannelPipeline} of the
     * {@link io.netty.channel.Channel}.
     */
    void fireExceptionCaught(Throwable cause);
}
public class DefaultChannelPipeline implements ChannelPipeline{

    private final DefaultChannelHandlerContext head;
    private final DefaultChannelHandlerContext tail;

    public DefaultChannelPipeline() {
        head = new DefaultChannelHandlerContext("HEAD");
        tail = new DefaultChannelHandlerContext("TAIL");
        head.next = tail;
        tail.prev = head;
    }

    @Override
    public ChannelPipeline addFirst(String name, ChannelHandler handler) {
        final DefaultChannelHandlerContext newNode;
        synchronized (this) {
            newNode = newHandlerNode(name, handler);
            addFirst0(newNode);
        }
        return this;
    }

    @Override
    public ChannelPipeline addLast(String name, ChannelHandler handler) {
        final DefaultChannelHandlerContext newNode;
        synchronized (this) {
            newNode = newHandlerNode(name, handler);
            addLast0(newNode);
        }
        return this;
    }

    @Override
    public void fireChannelRead(Object msg) {
        DefaultChannelHandlerContext.invokeChannelRead(head, msg);
    }

    @Override
    public void fireChannelReadComplete() {
        DefaultChannelHandlerContext.invokeChannelReadComplete(head);
    }

    @Override
    public void fireExceptionCaught(Throwable cause) {
        DefaultChannelHandlerContext.invokeExceptionCaught(head, cause);
    }

    private DefaultChannelHandlerContext newHandlerNode(String name, ChannelHandler handler) {
        return new DefaultChannelHandlerContext(name, handler);
    }

    private void addFirst0(DefaultChannelHandlerContext newNode) {
        DefaultChannelHandlerContext next = head.next;
        newNode.prev = head;
        newNode.next = next;
        head.next = newNode;
        next.prev = newNode;
    }

    private void addLast0(DefaultChannelHandlerContext newNode) {
        DefaultChannelHandlerContext prev = tail.prev;
        newNode.prev = prev;
        newNode.next = tail;
        prev.next = newNode;
        tail.prev = newNode;
    }
}
public interface ChannelHandlerContext {

    ChannelHandler handler();

    /**
     * A {@link io.netty.channel.Channel} received a message.
     *
     * This will result in having the {@link ChannelInboundHandler#channelRead(io.netty.channel.ChannelHandlerContext, Object)}
     * method  called of the next {@link ChannelInboundHandler} contained in the  {@link io.netty.channel.ChannelPipeline} of the
     * {@link io.netty.channel.Channel}.
     */
    void fireChannelRead(Object msg);

    /**
     * Triggers an {@link ChannelInboundHandler#channelReadComplete(io.netty.channel.ChannelHandlerContext)}
     * event to the next {@link ChannelInboundHandler} in the {@link io.netty.channel.ChannelPipeline}.
     */
    void fireChannelReadComplete();

    /**
     * A {@link io.netty.channel.Channel} received an {@link Throwable} in one of its inbound operations.
     *
     * This will result in having the  {@link ChannelInboundHandler#exceptionCaught(io.netty.channel.ChannelHandlerContext, Throwable)}
     * method  called of the next  {@link ChannelInboundHandler} contained in the  {@link io.netty.channel.ChannelPipeline} of the
     * {@link io.netty.channel.Channel}.
     */
    void fireExceptionCaught(Throwable cause);
}
public class DefaultChannelHandlerContext implements ChannelHandlerContext{

    volatile DefaultChannelHandlerContext next;
    volatile DefaultChannelHandlerContext prev;
    private ChannelHandler handler;
    private final String name;

    public DefaultChannelHandlerContext(String name) {
        this.name = name;
    }

    public DefaultChannelHandlerContext(String name, ChannelHandler handler) {
        this.name = name;
        this.handler = handler;
    }

    @Override
    public ChannelHandler handler() {
        return this.handler;
    }

    @Override
    public void fireChannelRead(Object msg) {
        invokeChannelRead(next, msg);
    }

    @Override
    public void fireChannelReadComplete() {
        invokeChannelReadComplete(next);
    }

    @Override
    public void fireExceptionCaught(Throwable cause) {
        invokeExceptionCaught(next, cause);
    }

    public static void invokeChannelRead(final DefaultChannelHandlerContext next, Object msg) {
        if (null != next){
            next.invokeChannelRead(msg);
        }
    }

    public static void invokeChannelReadComplete(DefaultChannelHandlerContext next) {
        if (null != next){
            next.invokeChannelReadComplete();
        }
    }

    public static void invokeExceptionCaught(DefaultChannelHandlerContext next, Throwable cause) {
        if (null != next){
            next.invokeExceptionCaught(cause);
        }
    }

    private void invokeChannelRead(Object msg) {
        if (null != handler){
            try {
                handler.channelRead(this, msg);
            } catch (Exception e){
                invokeExceptionCaught(e);
            }
        } else {
            fireChannelRead(msg);
        }
    }

    private void invokeChannelReadComplete() {
        if (null != handler){
            try {
                handler.channelReadComplete(this);
            } catch (Exception e){
                invokeExceptionCaught(e);
            }
        } else {
            fireChannelReadComplete();
        }
    }

    private void invokeExceptionCaught(final Throwable cause) {
        if (null != handler){
            try {
                handler.exceptionCaught(this, cause);
            } catch (Exception e){
                System.out.println(e.getMessage());
            }
        } else {
            fireExceptionCaught(cause);
        }
    }

}
public interface ChannelHandler {

    /**
     * Invoked when the current {@link io.netty.channel.Channel} has read a message from the peer.
     */
    void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception;

    /**
     * Invoked when the last message read by the current read operation has been consumed by
     * {@link #channelRead(io.netty.channel.ChannelHandlerContext, Object)}.  If {@link ChannelOption#AUTO_READ} is off, no further
     * attempt to read an inbound data from the current {@link Channel} will be made until
     * {@link io.netty.channel.ChannelHandlerContext#read()} is called.
     */
    void channelReadComplete(ChannelHandlerContext ctx) throws Exception;

    /**
     * Gets called if a {@link Throwable} was thrown.
     */
    void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
}
public interface Dispatcher {

    void doDispatcher(String msg);
}
public class DefaultDispatcher implements Dispatcher{

    private final ChannelPipeline channelPipeline;

    public DefaultDispatcher(ChannelPipeline channelPipeline) {
        this.channelPipeline = channelPipeline;
    }

    @Override
    public void doDispatcher(String msg) {
        try {
            channelPipeline.fireChannelRead(msg);
        }catch (Exception e){
            channelPipeline.fireExceptionCaught(e);
        }
        channelPipeline.fireChannelReadComplete();
    }
}

测试

public class HandlerOne implements ChannelHandler {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("HandlerOne................. Before");
        ctx.fireChannelRead(msg);
        System.out.println("HandlerOne................. After");
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("HandlerOne=======ReadComplete");
        ctx.fireChannelReadComplete();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("HandlerOne=======exceptionCaught");
        ctx.fireExceptionCaught(cause);
    }
}
public class HandlerTwo implements ChannelHandler {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("HandlerTwo................. Before");
        ctx.fireChannelRead(msg);
        System.out.println("HandlerTwo................. After");
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("HandlerTwo=======ReadComplete");
        ctx.fireChannelReadComplete();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("HandlerTwo=======exceptionCaught");
        ctx.fireExceptionCaught(cause);
    }
}
public class HandlerThree implements ChannelHandler {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("HandlerThree................. Before");
        ctx.fireChannelRead(msg);
        System.out.println("HandlerThree................. After");
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("HandlerThree=======ReadComplete");
        ctx.fireChannelReadComplete();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("HandlerThree=======exceptionCaught");
        ctx.fireExceptionCaught(cause);
    }
}

测试类

public class PipelineTest {
    public static void main(String[] args) {

        DefaultChannelPipeline pipeline = new DefaultChannelPipeline();
        pipeline.addLast("handlerOne", new HandlerOne());
        pipeline.addLast("handlerTwo", new HandlerTwo());
        pipeline.addLast("handlerThree", new HandlerThree());

        DefaultDispatcher dispatcher = new DefaultDispatcher(pipeline);

        dispatcher.doDispatcher("aaaaaaaaaaaaaaaaaa");

    }
}

输出结果:

HandlerOne................. Before
HandlerTwo................. Before
HandlerThree................. Before
HandlerThree................. After
HandlerTwo................. After
HandlerOne................. After
HandlerOne=======ReadComplete
HandlerTwo=======ReadComplete
HandlerThree=======ReadComplete

你可以在 HandlerOne 的 channelRead 方法中抛出异常,看下输出是怎样的。
欢迎在评论区留下你的总结

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值