本章将分析motan的序列化和底层通信相关部分的代码。
1.在上一章中,有一个getrefers的操作,来获取所有服务器的引用,每个服务器的引用都是由DefaultRpcReferer来创建的
public DefaultRpcReferer(Class<T> clz, URL url, URL serviceUrl) { super(clz, url, serviceUrl); endpointFactory = ExtensionLoader.getExtensionLoader(EndpointFactory.class).getExtension( url.getParameter(URLParamType.endpointFactory.getName(), URLParamType.endpointFactory.getValue()));//通过spi加载NettyEndpointFactory client = endpointFactory.createClient(url);//创建client }
2.NettyClient的创建过程及源码分析
public Client createClient(URL url) { LoggerUtil.info(this.getClass().getSimpleName() + " create client: url={}", url); return createClient(url, heartbeatClientEndpointManager);//创建client } private Client createClient(URL url, EndpointManager endpointManager) { Client client = innerCreateClient(url);//调用NettyEndpointFactory的创建client的方法 endpointManager.addEndpoint(client);//添加心跳管理 return client; } protected Client innerCreateClient(URL url) { return new NettyClient(url);//返回NettyClient对象 } public NettyClient(URL url) { super(url); maxClientConnection = url.getIntParameter(URLParamType.maxClientConnection.getName(), URLParamType.maxClientConnection.getIntValue()); timeMonitorFuture = scheduledExecutor.scheduleWithFixedDelay( new TimeoutMonitor("timeout_monitor_" + url.getHost() + "_" + url.getPort()), MotanConstants.NETTY_TIMEOUT_TIMER_PERIOD, MotanConstants.NETTY_TIMEOUT_TIMER_PERIOD, TimeUnit.MILLISECONDS); LoggerUtil.info("client's:"+url.getUri()); }
3.Netty相关的连接建立是通过open()方法进行的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
public
synchronized
boolean
open() {
if
(isAvailable()) {
return
true
;
}
// 初始化netty client bootstrap
initClientBootstrap();
// 初始化连接池
initPool();
LoggerUtil.info(
"NettyClient finish Open: url={}"
, url);
// 注册统计回调
StatsUtil.registryStatisticCallback(
this
);
// 设置可用状态
state = ChannelState.ALIVE;
return
state.isAliveState();
}
private
void
initClientBootstrap() {
bootstrap =
new
ClientBootstrap(channelFactory);
bootstrap.setOption(
"keepAlive"
,
true
);
bootstrap.setOption(
"tcpNoDelay"
,
true
);
// 实际上,极端情况下,connectTimeout会达到500ms,因为netty nio的实现中,是依赖BossThread来控制超时,
// 如果为了严格意义的timeout,那么需要应用端进行控制。
int
timeout = getUrl().getIntParameter(URLParamType.requestTimeout.getName(), URLParamType.requestTimeout.getIntValue());
if
(timeout <=
0
) {
throw
new
MotanFrameworkException(
"NettyClient init Error: timeout("
+ timeout +
") <= 0 is forbid."
,
MotanErrorMsgConstant.FRAMEWORK_INIT_ERROR);
}
bootstrap.setOption(
"connectTimeoutMillis"
, timeout);
// 最大响应包限制
final
int
maxContentLength = url.getIntParameter(URLParamType.maxContentLength.getName(),
URLParamType.maxContentLength.getIntValue());
bootstrap.setPipelineFactory(
new
ChannelPipelineFactory() {
public
ChannelPipeline getPipeline() {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast(
"decoder"
,
new
NettyDecoder(codec, NettyClient.
this
, maxContentLength));
//解码器
pipeline.addLast(
"encoder"
,
new
NettyEncoder(codec, NettyClient.
this
));
//编码器
pipeline.addLast(
"handler"
,
new
NettyChannelHandler(NettyClient.
this
,
new
MessageHandler() {
//业务处理的handler
@Override
public
Object handle(Channel channel, Object message) {
Response response = (Response) message;
NettyResponseFuture responseFuture = NettyClient.
this
.removeCallback(response.getRequestId());
//移调异步处理response信息
if
(responseFuture ==
null
) {
LoggerUtil.warn(
"NettyClient has response from server, but resonseFuture not exist, requestId={}"
,
response.getRequestId());
return
null
;
}
if
(response.getException() !=
null
) {
responseFuture.onFailure(response);
}
else
{
responseFuture.onSuccess(response);
}
return
null
;
}
}));
return
pipeline;
}
});
}
|
4.连接池
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
protected
void
initPool() {
poolConfig =
new
GenericObjectPool.Config();
//使用了GenericObjectPool作为连接池
poolConfig.minIdle =
url.getIntParameter(URLParamType.minClientConnection.getName(), URLParamType.minClientConnection.getIntValue());
//最小连接数,配置中为2个
poolConfig.maxIdle =
url.getIntParameter(URLParamType.maxClientConnection.getName(), URLParamType.maxClientConnection.getIntValue());
//最大连接数,配置中为10个
poolConfig.maxActive = poolConfig.maxIdle;
poolConfig.maxWait = url.getIntParameter(URLParamType.requestTimeout.getName(), URLParamType.requestTimeout.getIntValue());
poolConfig.lifo = url.getBooleanParameter(URLParamType.poolLifo.getName(), URLParamType.poolLifo.getBooleanValue());
poolConfig.minEvictableIdleTimeMillis = defaultMinEvictableIdleTimeMillis;
poolConfig.softMinEvictableIdleTimeMillis = defaultSoftMinEvictableIdleTimeMillis;
poolConfig.timeBetweenEvictionRunsMillis = defaultTimeBetweenEvictionRunsMillis;
factory = createChannelFactory();
//创建chanalfactory
pool =
new
GenericObjectPool(factory, poolConfig);
boolean
lazyInit = url.getBooleanParameter(URLParamType.lazyInit.getName(), URLParamType.lazyInit.getBooleanValue());
if
(!lazyInit) {
for
(
int
i =
0
; i < poolConfig.minIdle; i++) {
//初始化2个长连接
try
{
pool.addObject();
LoggerUtil.info(
"init client's connection :"
+i);
}
catch
(Exception e) {
LoggerUtil.error(
"NettyClient init pool create connect Error: url="
+ url.getUri(), e);
}
}
}
}
|
5.NettyChannelFactory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public
class
NettyChannelFactory
extends
BasePoolableObjectFactory {
private
String factoryName =
""
;
private
NettyClient nettyClient;
public
NettyChannelFactory(NettyClient nettyClient) {
super
();
this
.nettyClient = nettyClient;
this
.factoryName =
"NettyChannelFactory_"
+ nettyClient.getUrl().getHost() +
"_"
+ nettyClient.getUrl().getPort();
}
@Override
public
Object makeObject()
throws
Exception {
//创建连接时会调用
NettyChannel nettyChannel =
new
NettyChannel(nettyClient);
//创建channel
nettyChannel.open();
//打开channel
return
nettyChannel;
}
}
|
6.NettyChannel
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
public
class
NettyChannel
implements
com.weibo.api.motan.transport.Channel {
private
volatile
ChannelState state = ChannelState.UNINIT;
private
NettyClient nettyClient;
private
org.jboss.netty.channel.Channel channel =
null
;
private
InetSocketAddress remoteAddress =
null
;
private
InetSocketAddress localAddress =
null
;
public
NettyChannel(NettyClient nettyClient) {
this
.nettyClient = nettyClient;
this
.remoteAddress =
new
InetSocketAddress(nettyClient.getUrl().getHost(), nettyClient.getUrl().getPort());
//服务器host和port
}
public
synchronized
boolean
open() {
//打开连接
if
(isAvailable()) {
LoggerUtil.warn(
"the channel already open, local: "
+ localAddress +
" remote: "
+ remoteAddress +
" url: "
+ nettyClient.getUrl().getUri());
return
true
;
}
try
{
ChannelFuture channleFuture = nettyClient.getBootstrap().connect(
new
InetSocketAddress(nettyClient.getUrl().getHost(), nettyClient.getUrl().getPort()));
//打开连接
long
start = System.currentTimeMillis();
int
timeout = nettyClient.getUrl().getIntParameter(URLParamType.connectTimeout.getName(), URLParamType.connectTimeout.getIntValue());
if
(timeout <=
0
) {
throw
new
MotanFrameworkException(
"NettyClient init Error: timeout("
+ timeout +
") <= 0 is forbid."
,
MotanErrorMsgConstant.FRAMEWORK_INIT_ERROR);
}
// 不去依赖于connectTimeout
boolean
result = channleFuture.awaitUninterruptibly(timeout, TimeUnit.MILLISECONDS);
boolean
success = channleFuture.isSuccess();
if
(result && success) {
channel = channleFuture.getChannel();
if
(channel.getLocalAddress() !=
null
&& channel.getLocalAddress()
instanceof
InetSocketAddress) {
localAddress = (InetSocketAddress) channel.getLocalAddress();
}
state = ChannelState.ALIVE;
return
true
;
}
boolean
connected =
false
;
if
(channleFuture.getChannel() !=
null
){
connected = channleFuture.getChannel().isConnected();
}
if
(channleFuture.getCause() !=
null
) {
channleFuture.cancel();
throw
new
MotanServiceException(
"NettyChannel failed to connect to server, url: "
+ nettyClient.getUrl().getUri()+
", result: "
+ result +
", success: "
+ success +
", connected: "
+ connected, channleFuture.getCause());
}
else
{
channleFuture.cancel();
throw
new
MotanServiceException(
"NettyChannel connect to server timeout url: "
+ nettyClient.getUrl().getUri() +
", cost: "
+ (System.currentTimeMillis() - start) +
", result: "
+ result +
", success: "
+ success +
", connected: "
+ connected);
}
}
catch
(MotanServiceException e) {
throw
e;
}
catch
(Exception e) {
throw
new
MotanServiceException(
"NettyChannel failed to connect to server, url: "
+ nettyClient.getUrl().getUri(), e);
}
finally
{
if
(!state.isAliveState()) {
nettyClient.incrErrorCount();
//增加错误次数
}
}
}
}
|
本章知识点总结:
1.使用netty作为底层通讯框架;
2.每个refer对应一个nettyclient和一个nettychannel,nettychannel是由工厂类创建;
3.每个client在初始化时,最少创建2个长连接,由配置决定;
4.使用了GenericObjectPool来作为连接池;
5.当每个client的连续调用出错数达到阀值时,将自动设置此client为不可用;
6.心跳操作由客户端发起,只针对不可用状态的client。