本章将分析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。