从前面一篇创建注册中心的流程当中,我们知道在从注册中心获取到provider的连接信息后,会通过连接创建Invoker。代码见com.alibaba.dubbo.registry.integration.RegistryDirectory的toInvokers方法:
// protocol实现为com.alibaba.dubbo.rpc.Protocol$Adpative,
// 之前已经讲过,这是dubbo在运行时动态创建的一个类;
// serviceType为服务类的class, 如demo中的com.alibaba.dubbo.demo.DemoService;
// providerUrl为服务提供方注册的连接;
// url为providerUrl与消费方参数的合并
invoker = new InvokerDelegete<T>(protocol.refer(serviceType, url), url, providerUrl);
此处url的protocol为dubbo,因此protocol.refer最终会调用com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol.refer,同时Protocol存在两个wrapper类,分别为:
com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper、
com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper。在dubbo中存在wrapper类的类会被wrapper实例包装后返回,因此在protocol.refer方法调用的时候,会先经过wrapper类。由于这里的复杂性,我们先不讲wrapper类里的refer实现,直接跳到DubboProtocol.refer。
url的demo如下:
dubbo://30.33.47.127:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-consumer&check=false&....
DubboProtocol的refer代码如下:
public <T> Invoker<T> refer(Class<T> serviceType, URL url) throws RpcException {
// 创建一个DubboInvoker
DubboInvoker<T> invoker = new DubboInvoker<T>(serviceType, url, getClients(url), invokers);
// 将invoker加入到invokers这个Set中
invokers.add(invoker);
return invoker;
}
// 创建连接Client,该Client主要负责建立连接,发送数据等
private ExchangeClient[] getClients(URL url){
//是否共享连接
boolean service_share_connect = false;
int connections = url.getParameter(Constants.CONNECTIONS_KEY, 0);
// 如果connections不配置,则共享连接,否则每服务每连接,
// 共享连接的意思是对于同一个ip+port的所有服务只创建一个连接,
// 如果是非共享连接则每个服务+(ip+port)创建一个连接
if (connections == 0){
service_share_connect = true;
connections = 1;
}
ExchangeClient[] clients = new ExchangeClient[connections];
for (int i = 0; i < clients.length; i++) {
if (service_share_connect){
clients[i] = getSharedClient(url);
} else {
clients[i] = initClient(url);
}
}
return clients;
}
/**
*获取共享连接
*/
private ExchangeClient getSharedClient(URL url){
// 以address(ip:port)为key进行缓存
String key = url.getAddress();
ReferenceCountExchangeClient client = referenceClientMap.get(key);
if ( client != null ){
// 如果连接存在了则引用数加1,引用数表示有多少个服务使用了此client,
// 当某个client调用close()时,引用数减一,
// 如果引用数大于0,表示还有服务在使用此连接, 不会真正关闭client
// 如果引用数为0,表示没有服务在用此连接,此时连接彻底关闭
if ( !client.isClosed()){
client.incrementAndGetCount();
return client;
} else {
logger.warn(new IllegalStateException("client is closed,but stay in clientmap .client :"+ client));
referenceClientMap.remove(key);
}
}
// 调用initClient来初始化Client
ExchangeClient exchagneclient = initClient(url);
// 使用ReferenceCountExchangeClient进行包装
client = new ReferenceCoun