Dubbo源码学习08

Dubbo的网络传输层支持Netty、Mina、Grizzly类型的NIO框架;那么Dubbo是怎么屏蔽三种NIO框架底层细节实现,做到统一处理Channel的。下面我们拿Netty与Mina实现网络传输为例,来简单总结下

NettyServer.java

@Override
    protected void doOpen() throws Throwable {
        //启动器
        bootstrap = new ServerBootstrap();
        //Reactor线程模型之创建Selector用于不断监听Socket连接、客户端读写操作
        bossGroup = new NioEventLoopGroup(1, new DefaultThreadFactory("NettyServerBoss", true));
        //用一个线程池即workers,负责处理Selector派发的读写操作。
        workerGroup = new NioEventLoopGroup(getUrl().getPositiveParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS),
                new DefaultThreadFactory("NettyServerWorker", true));
        //定义NettyServerHandler,处理客户端channel连接到服务端的相关事件,不明白自行学习Netty
        final NettyServerHandler nettyServerHandler = new NettyServerHandler(getUrl(), this);
        channels = nettyServerHandler.getChannels();
        //配置启动器
        bootstrap.group(bossGroup, workerGroup)
                //指定服务端的channel类型
                .channel(NioServerSocketChannel.class)
                .childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE)
                .childOption(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
                .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        //Netty编解码适配器
                        NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
                        //添加编码、解码handler还有与业务有关的handler
                        ch.pipeline()//.addLast("logging",new LoggingHandler(LogLevel.INFO))//for debug
                                .addLast("decoder", adapter.getDecoder())
                                .addLast("encoder", adapter.getEncoder())
                                .addLast("handler", nettyServerHandler);
                    }
                });
        //
        ChannelFuture channelFuture = bootstrap.bind(getBindAddress());
        channelFuture.syncUninterruptibly();
        channel = channelFuture.channel();

    }

如果我们了解Netty怎么构构建一个简单的网络程序,上面代码不难理解

MinaServer.java

@Override
    protected void doOpen() throws Throwable {
        // set thread pool.
        acceptor = new SocketAcceptor(getUrl().getPositiveParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS),
                Executors.newCachedThreadPool(new NamedThreadFactory("MinaServerWorker",
                        true)));
        // config
        SocketAcceptorConfig cfg = (SocketAcceptorConfig) acceptor.getDefaultConfig();
        cfg.setThreadModel(ThreadModel.MANUAL);
        // set codec.
        acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new MinaCodecAdapter(getCodec(), getUrl(), this)));

        acceptor.bind(getBindAddress(), new MinaHandler(getUrl(), this));
    }

Netty和Mina的服务端实现

1.开启服务方式不太一样

2.都需要ChannelHandler,需要继承org.jboss.netty.channel.SimpleChannelHandler(或者其他方式),来处理org.jboss.netty.channel.Channel的连接读写事件 对于mina来说:需要继承org.apache.mina.common.IoHandlerAdapter(或者其他方式),来处理org.apache.mina.common.IoSession的连接读写事件

3.Channel不同,Netty用的是io.netty.channel.Channel进行数据的传输,Mina用的是org.apache.mina.common.IoSession

4.编解码器;Netty需要继承MessageToByteEncoder、ByteToMessageDecoder;Mina需要继承IoFilterAdapter类;

5.编解码器的不同必然带来不同字节缓冲区实现不同,Netty最终会将编码数据写入到io.netty.buffer.ByteBuf,Mina最终会将编码的数据通过ProtocolEncoderOutput写入到org.apache.mina.common.ByteBuffer中,

Dubbo是怎么实现统一的

  • Channel
public interface Channel extends Endpoint {

    /**
     * get remote address.
     *
     * @return remote address.
     */
    InetSocketAddress getRemoteAddress();

    /**
     * is connected.
     *
     * @return connected
     */
    boolean isConnected();

    /**
     * has attribute.
     *
     * @param key key.
     * @return has or has not.
     */
    boolean hasAttribute(String key);

    /**
     * get attribute.
     *
     * @param key key.
     * @return value.
     */
    Object getAttribute(String key);

    /**
     * set attribute.
     *
     * @param key   key.
     * @param value value.
     */
    void setAttribute(String key, Object value);

    /**
     * remove attribute.
     *
     * @param key key.
     */
    void removeAttribute(String key);

}

1.针对netty,上述Channel的实现为NettyChannel,内部含有一个netty自己的org.jboss.netty.channel.Channel channel对象,即该com.alibaba.dubbo.remoting.Channel接口的功能实现全部委托为底层的org.jboss.netty.channel.Channel channel对象来实现

2. 针对mina,上述Channel实现为MinaChannel,内部包含一个mina自己的org.apache.mina.common.IoSession session对象,即该com.alibaba.dubbo.remoting.Channel接口的功能实现全部委托为底层的org.apache.mina.common.IoSession session对象来实现

  • ChannelHandler
ublic interface ChannelHandler {

    /**
     * on channel connected.
     *
     * @param channel channel.
     */
    void connected(Channel channel) throws RemotingException;

    /**
     * on channel disconnected.
     *
     * @param channel channel.
     */
    void disconnected(Channel channel) throws RemotingException;

    /**
     * on message sent.
     *
     * @param channel channel.
     * @param message message.
     */
    void sent(Channel channel, Object message) throws RemotingException;

    /**
     * on message received.
     *
     * @param channel channel.
     * @param message message.
     */
    void received(Channel channel, Object message) throws RemotingException;

    /**
     * on exception caught.
     *
     * @param channel   channel.
     * @param exception exception.
     */
    void caught(Channel channel, Throwable exception) throws RemotingException;

}

1.针对Netty,ChannelHandler的服务端的NettyServerHandler通过继承ChannelDupexHandler,接收连接读写事件并委托给自身的com.alibaba.dubbo.remoting.ChannelHandler,客户端则是NettyClientHandler

@Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler);
        try {
            handler.received(channel, msg);
        } finally {
            NettyChannel.removeChannelIfDisconnected(ctx.channel());
        }
    }

2.针对Mina,ChannelHandler的服务端实现MinaHandler通过继承自IoHandlerAdapter,接收连接读写事件并委托给自己的com.alibaba.dubbo.remoting.ChannelHandler,

@Override
    public void sessionOpened(IoSession session) throws Exception {
        MinaChannel channel = MinaChannel.getOrAddChannel(session, url, handler);
        try {
            handler.connected(channel);
        } finally {
            MinaChannel.removeChannelIfDisconnected(session);
        }
    }
  • ChannelBuffer:该接口的设计参考io.netty.buffer.ByteBuf设计,注释和方法基本相同
  • AbstractChannelBuffer:readerIndex和writerIndex用于维护读取和写入索引,markedReaderIndex和markedWriterIndex,当对缓冲区进行读写操作时,可能需要对之前的操作进行回滚。
 /**
     * 读索引
     */
    private int readerIndex;
    /**
     * 写索引
     */
    private int writerIndex;
    /**
     * 标记读索引
     */
    private int markedReaderIndex;
    /**
     * 标记写索引
     */
    private int markedWriterIndex;

1.针对Netty,字节缓冲区采用NettyBackedChannelBuffer实现,该类内部持有一个io.netty.buffer.ByteBuf对象,用于实现对字节读取操作,Dubbo的编解码最终也是对NettyBackedChannelBuffer中的ByteBuf对象的操作

2.针对Mina,字节缓冲区采用DynamicChannelBuffer实现,该类内部维护了ChannelBufferFactory和ChannelBuffer类型的对象,ChannelBuffer的创建通过ChannelBufferFactory实现。

/**
     * 通道缓存工厂
     */
    private final ChannelBufferFactory factory;
    /**
     * 通道缓存区
     */
    private ChannelBuffer buffer;

对于编解码统一使用ChannelBuffer对象进行字节的处理接口。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值