fescar源码分析-AbstractRpcRemotingClient

在fescar源码分析-AbstractRpcRemoting介绍了fescar对响应请求及向送请求的封装。下面分析AbstractRpcRemoting的子类AbstractRpcRemotingClientAbstractRpcRemotingClient在父类基础针对RPC调用的客户端做进一步的封装。

构造方法

    public AbstractRpcRemotingClient(NettyClientConfig nettyClientConfig, final EventExecutorGroup eventExecutorGroup,
            final ThreadPoolExecutor messageExecutor) {
        super(messageExecutor);
        if (null == nettyClientConfig) {
            nettyClientConfig = new NettyClientConfig();
            if (LOGGER.isInfoEnabled()) {
                LOGGER.info("use default netty client config.");
            }
        }
        this.nettyClientConfig = nettyClientConfig;//1
        int selectorThreadSizeThreadSize = this.nettyClientConfig.getClientSelectorThreadSize();
        this.eventLoopGroupWorker = new NioEventLoopGroup(selectorThreadSizeThreadSize, new NamedThreadFactory(
                getThreadPrefix(this.nettyClientConfig.getClientSelectorThreadPrefix()), selectorThreadSizeThreadSize));//2
        this.defaultEventExecutorGroup = eventExecutorGroup;
    }
  • 1根据配置文件,初始化RPC客户端配置。
  • 2根据配置文件中的参数,设置EventLoopGroup
  • 3由子类创建的eventExecutorGroup对象,设置EventExecutorGroup

其中关于EventLoopGroup类型的属性,主要是用于处理NIO中的accept,read及write操作,而EventExecutorGroup则是用于执行Handler,如下图所示:


image
image

重载父类方法

重载init()方法

首先AbstractRpcRemoting重载了AbstractRpcRemotinginit()方法(初始化一个线程池,处理异步RPC请求中的超时缓存数据),添加了一些新的处理:


    @Override
    public void init() {
        NettyPoolableFactory keyPoolableFactory = new NettyPoolableFactory(this);
        nettyClientKeyPool = new GenericKeyedObjectPool(keyPoolableFactory);
        nettyClientKeyPool.setConfig(getNettyPoolConfig());//1
        serviceManager = new ServiceManagerStaticConfigImpl();//2
        super.init();
    }
  • 1.设置了AbstractRpcRemoting类中属性nettyClientKeyPool,该属性是GenericKeyedObjectPool类型。
GenericKeyedObjectPool provides robust pooling functionality for keyed objects. 
A GenericKeyedObjectPool can be viewed as a map of pools, keyed on the (unique) key values provided to the prepare Pool, add Object or borrow Object methods. 
Each time a new key value is provided to one of these methods, a new pool is created under the given key to be managed by the containing GenericKeyedObjectPool. 
  • 2.设置了AbstractRpcRemoting类中属性serviceManager,该属性是ServiceManager类型。
    该属性应该是为了后期实现服务的注册与发现功能,但现在暂时没有实现。
ServiceManager :Service Registry and Discovery

重载dispatch()方法

dispatch在父类是一个抽象方法,具体逻辑需要子类来实现。AbstractRpcRemotingClient通过注册的ClientMessageListener事件监听器实现对消息做具体的处理。

 protected ClientMessageListener clientMessageListener;
......
    @Override
    public void dispatch(long msgId, ChannelHandlerContext ctx, Object msg) {
        if (clientMessageListener != null) {
            String remoteAddress = NetUtil.toStringAddress(ctx.channel().remoteAddress());
            clientMessageListener.onMessage(msgId, remoteAddress, msg, this);
        }
    }

重载channelRead()方法

在处理父类channelRead()方法逻辑之前,先判断一下接收到的消息是不是心跳回复消息,如果是则不再处理下面的请求。

            if (rpcMessage.getBody() == HeartbeatMessage.PONG) {
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("received PONG from " + ctx.channel().remoteAddress());
                }
                return;
            }

如果是合并回复消息,则批量处理回复信息。

        if (((RpcMessage) msg).getBody() instanceof MergeResultMessage) {
            MergeResultMessage results = (MergeResultMessage) ((RpcMessage) msg).getBody();
            MergedWarpMessage mergeMessage = (MergedWarpMessage) mergeMsgMap.remove(((RpcMessage) msg).getId());
            int num = mergeMessage.msgs.size();
            for (int i = 0; i < num; i++) {
                long msgId = mergeMessage.msgIds.get(i);
                MessageFuture future = futures.remove(msgId);
                if (future == null) {
                    if (LOGGER.isInfoEnabled()) {
                        LOGGER.info("msg:" + msgId + " is not found in futures.");
                    }
                } else {
                    future.setResultMessage(results.getMsgs()[i]);
                }
            }
            return;
        }

除了重载父类方法,该类主要实现了RemotingService, RegisterMsgListener, ClientMessageSender三个接口。图下所示:

image.png

下面具体讲一下各个接口的定义以及AbstractRpcRemotingClient对接口的具体实现:

实现RemotingService接口

实现RPC客户端的启停操作。在AbstractRpcRemotingClient类中主要是通过操作内部的Bootstrap属性(可以通过Netty引导客户端和无连接协议了解到,Bootstrap是Netty创建客户端的引导类),

image.png

start()

实现RPC客户端的启动。

    private final Bootstrap bootstrap = new Bootstrap();

Bootstrap主要需要设置以下属性:

* EventLoopGroup 
* Channel
* ChannelHandler
* 及一些参数配置等

为了实现这些参数的可配置化,AbstractRpcRemotingClient使用了NettyClientConfig类。
AbstractRpcRemotingClient分别通过以下方式来设置Bootstrap的这些属性:

->EventLoopGroup

AbstractRpcRemotingClient在创建时指定EventLoopGroupNioEventLoopGroup的实例。

        this.eventLoopGroupWorker = new NioEventLoopGroup(selectorThreadSizeThreadSize, new NamedThreadFactory(
                getThreadPrefix(this.nettyClientConfig.getClientSelectorThreadPrefix()), selectorThreadSizeThreadSize));

->Channel

Channel实例类型将通过nettyClientConfig对象的属性值来指定。

                .channel(nettyClientConfig.getClientChannelClazz())//

->ChannelHandler

首先会通过配置属性判断是否使用连接池,如果使用连接池。则为每个连接地址创建一个FixedChannelPool对象。从字面意思理解就是一个通道池子。

        if (nettyClientConfig.isUseConnPool()) {
            clientChannelPool = new AbstractChannelPoolMap() {//0
                @Override
                protected FixedChannelPool newPool(InetSocketAddress key) {
                    FixedChannelPool fixedClientChannelPool = new FixedChannelPool(bootstrap.remoteAddress(key),
                            new DefaultChannelPoolHandler() {
                                @Override
                                public void channelCreated(Channel ch) throws Exception {
                                    super.channelCreated(ch);
                                    final ChannelPipeline pipeline = ch.pipeline();
                                    pipeline.addLast(defaultEventExecutorGroup,//1
                                            new IdleStateHandler(nettyClientConfig.getChannelMaxReadIdleSeconds(),
                                                    nettyClientConfig.getChannelMaxWriteIdleSeconds(),
                                                    nettyClientConfig.getChannelMaxAllIdleSeconds()));//2.1
                                    pipeline.addLast(defaultEventExecutorGroup, new RpcClientHandler());//2.2
                                }
                            }, ChannelHealthChecker.ACTIVE, AcquireTimeoutAction.FAIL,
                            nettyClientConfig.getMaxAcquireConnMills(), nettyClientConfig.getPerHostMaxConn(),
                            nettyClientConfig.getPendingConnSize(), false);
                    return fixedClientChannelPool;

                }
            };
  • 0.继承AbstractChannelPoolMap类,实现newPool(InetSocketAddress key)方法,创建一个FixedChannelPool对象。
    1. 池中的Channel对象会使用创建的DefaultEventExecutorGroup对象来执行ChannelHandler。
        if (this.defaultEventExecutorGroup == null) {
            this.defaultEventExecutorGroup = new DefaultEventExecutorGroup(nettyClientConfig.getClientWorkerThreads(),
                    new NamedThreadFactory(getThreadPrefix(nettyClientConfig.getClientWorkerThreadPrefix()),
                            nettyClientConfig.getClientWorkerThreads()));
        }
  • 2.池中的Channel对象的ChannelPipeline设置了:IdleStateHandlerRpcClientHandler两个ChannelHandler。
    (注:ChannelHandler为fescar自定义ChannelHandler,但从代码来看目前并没有对RPC客户端对线程池的支持实现完。后面将不再分析Channel池相关的代码)。

如果不使用连接池,则为Bootstrap对象设置了:IdleStateHandlerMessageCodecHandler两个ChannelHandler。

bootstrap.handler(new ChannelInitializer() {

                @Override
                public void initChannel(SocketChannel ch) {
                    ChannelPipeline pipeline = ch.pipeline();
                    pipeline.addLast(new IdleStateHandler(nettyClientConfig.getChannelMaxReadIdleSeconds(),
                            nettyClientConfig.getChannelMaxWriteIdleSeconds(),
                            nettyClientConfig.getChannelMaxAllIdleSeconds()))//
                    .addLast(new MessageCodecHandler());//添加消息加解码器
                    if (null != channelHandlers) {
                        addChannelPipelineLast(ch, channelHandlers);
                    }
                }
            });

shutdown()

就是在PRC客户端关闭的时候,关闭相关资源。

    public void shutdown() {
        try {
            if (null != clientChannelPool) {
                clientChannelPool.close();//1关闭通道池。
            }
            this.eventLoopGroupWorker.shutdownGracefully();//2关闭通道使用的EventLoopGroup。
            if (this.defaultEventExecutorGroup != null) {
                this.defaultEventExecutorGroup.shutdownGracefully();//3关闭通道池使用的EventLoopGroup池。
            }
            super.destroy();
        } catch (Exception exx) {
            LOGGER.error("shutdown error:" + exx.getMessage());
        }
    }

RegisterMsgListener

image.png

该接口主要用于,根据RPC请求返回的信息,判断调用成功或失败的状态触发接口方法,实现后续业务逻辑处理:

NettyPoolableFactory.java
......
        try {
            response = rpcRemotingClient.sendAsyncRequestWithResponse(null, tmpChannel, key.getMessage());
            if (!isResponseSuccess(response, key.getTransactionRole())) {
                rpcRemotingClient.onRegisterMsgFail(key.getAddress(), tmpChannel, response, key.getMessage());
            } else {
                channelToServer = tmpChannel;
                rpcRemotingClient.onRegisterMsgSuccess(key.getAddress(), tmpChannel, response,
                    key.getMessage());
            }
        } catch (Exception exx) {
......

AbstractRpcRemotingClient并没有实现RegisterMsgListener接口,而是交由子类来实现。

ClientMessageSender

image.png

该接口主要用于实现发送请求,并返回请求结果的逻辑实现。

你可能感兴趣的:(fescar源码分析-AbstractRpcRemotingClient)