在fescar源码分析-AbstractRpcRemoting介绍了fescar对响应请求及向送请求的封装。下面分析AbstractRpcRemoting
的子类AbstractRpcRemotingClient
,AbstractRpcRemotingClient
在父类基础针对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,如下图所示:
重载父类方法
重载init()方法
首先AbstractRpcRemoting
重载了AbstractRpcRemoting
的init()
方法(初始化一个线程池,处理异步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
三个接口。图下所示:
下面具体讲一下各个接口的定义以及
AbstractRpcRemotingClient
对接口的具体实现:
实现RemotingService接口
实现RPC客户端的启停操作。在AbstractRpcRemotingClient
类中主要是通过操作内部的Bootstrap
属性(可以通过Netty引导客户端和无连接协议了解到,Bootstrap
是Netty创建客户端的引导类),
start()
实现RPC客户端的启动。
private final Bootstrap bootstrap = new Bootstrap();
Bootstrap
主要需要设置以下属性:
* EventLoopGroup
* Channel
* ChannelHandler
* 及一些参数配置等
为了实现这些参数的可配置化,AbstractRpcRemotingClient
使用了NettyClientConfig类。
而AbstractRpcRemotingClient
分别通过以下方式来设置Bootstrap
的这些属性:
->EventLoopGroup
AbstractRpcRemotingClient
在创建时指定EventLoopGroup
为NioEventLoopGroup
的实例。
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
对象。 -
- 池中的Channel对象会使用创建的DefaultEventExecutorGroup对象来执行ChannelHandler。
if (this.defaultEventExecutorGroup == null) {
this.defaultEventExecutorGroup = new DefaultEventExecutorGroup(nettyClientConfig.getClientWorkerThreads(),
new NamedThreadFactory(getThreadPrefix(nettyClientConfig.getClientWorkerThreadPrefix()),
nettyClientConfig.getClientWorkerThreads()));
}
- 2.池中的Channel对象的ChannelPipeline设置了:
IdleStateHandler
和RpcClientHandler
两个ChannelHandler。
(注:ChannelHandler为fescar自定义ChannelHandler,但从代码来看目前并没有对RPC客户端对线程池的支持实现完。后面将不再分析Channel池相关的代码)。
如果不使用连接池,则为Bootstrap
对象设置了:IdleStateHandler
和 MessageCodecHandler
两个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
该接口主要用于,根据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
该接口主要用于实现发送请求,并返回请求结果的逻辑实现。