dubbo源码分析4-- ReferenceBean 获取消费者代理对象

主要工作

  1. 获取invoker对象
    a)注册消费端的临时节点
    b) 订阅以下的节点
    /dubbo/com.test.ITestService/providers
    /dubbo/com.test.ITestService/configurators
    /dubbo/com.test.ITestService/routers
    c) 当这些节点下的子节点发生变化: 刷新本地的RequestDirector的本地urlInvokerMap列表
    第一次初始化invoker,创建DubboInvoker。启动netty客户端连接

  2. 将invoker包装在代理对象Proxy$0中。返回代理对象

流程

主流程
dubbo源码分析4-- ReferenceBean 获取消费者代理对象_第1张图片
消费端接口初始化或者有提供者节点变化时,通知更新本地zookeeper缓存文件
dubbo源码分析4-- ReferenceBean 获取消费者代理对象_第2张图片
消费端接口初始化或者有提供者节点变化时,通知更新本地的invoker列表 urlInvokerMap
dubbo源码分析4-- ReferenceBean 获取消费者代理对象_第3张图片
在更新本地的invoker列表时,没有生成过Invoker,需要指定Invoker且netty客户端连接服务端
dubbo源码分析4-- ReferenceBean 获取消费者代理对象_第4张图片

入口

ReferenceBean 实现了FactoryBean, 那么在从io容器获取Bean时,就调用了Object getObject()
private transient volatile T ref; //保存代理对象
当有对象时,直接返回,否则初始化

public synchronized T get() {
    if (destroyed) {
         throw new IllegalStateException("Already destroyed!");
     }
     if (ref == null) {
         init();
     }
     return ref;
 }

init()组装参数,最终调用 ref = createProxy(map);

  • 封装urls
    用户指定URL,指定的URL可能是对点对直连地址;否则通过注册中心配置拼装URL
//用户指定URL,指定的URL可能是对点对直连地址,也可能是注册中心URL
if (url != null && url.length() > 0) { 
    String[] us = Constants.SEMICOLON_SPLIT_PATTERN.split(url);
    if (us != null && us.length > 0) {
        for (String u : us) {
            URL url = URL.valueOf(u);
            if (url.getPath() == null || url.getPath().length() == 0) {
                url = url.setPath(interfaceName);
            }
            if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
                urls.add(url.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map)));
            } else {
                urls.add(ClusterUtils.mergeUrl(url, map));
            }
        }
    }
} else { 
    //通过注册中心配置拼装URL
    List us = loadRegistries(false);
    if (us != null && !us.isEmpty()) {
        for (URL u : us) {
            URL monitorUrl = loadMonitor(u);
            if (monitorUrl != null) {
                map.put(Constants.MONITOR_KEY, URL.encode(monitorUrl.toFullString()));
            }
            urls.add(u.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map)));
        }
    }
    if (urls == null || urls.isEmpty()) {
        throw new IllegalStateException();
    }
}
  • 获取invoker

if (urls.size() == 1) {
     invoker = refprotocol.refer(interfaceClass, urls.get(0));
  } else {
      List> invokers = new ArrayList>();
      URL registryURL = null;
      for (URL url : urls) {
          invokers.add(refprotocol.refer(interfaceClass, url));
          if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
              registryURL = url; 
          }
      }
      //有注册中心的地址, StaticDirectory
      if (registryURL != null) { 
          URL u = registryURL.addParameter(Constants.CLUSTER_KEY, AvailableCluster.NAME);
          invoker = cluster.join(new StaticDirectory(u, invokers));
      } else { // not a registry url
          invoker = cluster.join(new StaticDirectory(invokers));
      }
  }

获取invoker对象

refprotocol.refer(interfaceClass, url)
refprotocol这里的对象是RegistryProtocol

1.获取Registry:ZookeeperRegistry

//将registry协议改成zookeeper。
 url = url.setProtocol(url.getParameter(Constants.REGISTRY_KEY, Constants.DEFAULT_REGISTRY)).removeParameter(Constants.REGISTRY_KEY);
 Registry registry = registryFactory.getRegistry(url);
  if (RegistryService.class.equals(type)) {
  	return proxyFactory.getInvoker((T) registry, type, url);
  }

2.向zookeeper注册consumer://10.118.14.24/com.test.ITestService节点
registry.register(subscribeUrl.addParameters(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY,
Constants.CHECK_KEY, String.valueOf(false)));
a)将url保存到注册列表中
b)创建提供者的临时节点
c)出现异常时,开启启动时检测,直接抛出异常;否则记录到failedRegistered,等待定时重新注册
3.创建RegistryDirectory,并且订阅consumer://10.118.14.24/com.test.ITestService

consumer://10.118.14.24/com.test.ITestService?category=providers,configurators,routers&side=consumer…

RegistryDirectory directory = new RegistryDirectory(type, url);
 directory.setRegistry(registry);
 directory.setProtocol(protocol);
 URL subscribeUrl = new URL(Constants.CONSUMER_PROTOCOL, NetUtils.getLocalHost(), 0,
   type.getName(), directory.getUrl().getParameters());
 //加参数category:providers,configurators,routers
 directory.subscribe(subscribeUrl.addParameter(Constants.CATEGORY_KEY, 
         Constants.PROVIDERS_CATEGORY 
         + "," + Constants.CONFIGURATORS_CATEGORY 
         + "," + Constants.ROUTERS_CATEGORY));

4.cluster.join(directory);
默认是FailoverCluster, 所以返回的invoker对象是MockClusterInvoker(FailoverClusterInvoker)

mock=com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterWrapper
failover=com.alibaba.dubbo.rpc.cluster.support.FailoverCluster
failfast=com.alibaba.dubbo.rpc.cluster.support.FailfastCluster
failsafe=com.alibaba.dubbo.rpc.cluster.support.FailsafeCluster
failback=com.alibaba.dubbo.rpc.cluster.support.FailbackCluster
forking=com.alibaba.dubbo.rpc.cluster.support.ForkingCluster
available=com.alibaba.dubbo.rpc.cluster.support.AvailableCluster
mergeable=com.alibaba.dubbo.rpc.cluster.support.MergeableCluster
broadcast=com.alibaba.dubbo.rpc.cluster.support.BroadcastCluster

创建代理对象

上面创建了invoker对象
proxyFactory.getProxy(invoker)
StubProxyFactoryWrapper(JavassistProxyFactory)

stub=com.alibaba.dubbo.rpc.proxy.wrapper.StubProxyFactoryWrapper
jdk=com.alibaba.dubbo.rpc.proxy.jdk.JdkProxyFactory
javassist=com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory
  • JavassistProxyFactory创建代理对象

获取代理方法

public  T getProxy(Invoker invoker, Class[] interfaces) {
     return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
  }

拦截器

public class InvokerInvocationHandler implements InvocationHandler {

    private final Invoker invoker;
    
    public InvokerInvocationHandler(Invoker handler){
        this.invoker = handler;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        Class[] parameterTypes = method.getParameterTypes();
        if (method.getDeclaringClass() == Object.class) {
            return method.invoke(invoker, args);
        }
        if ("toString".equals(methodName) && parameterTypes.length == 0) {
            return invoker.toString();
        }
        if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
            return invoker.hashCode();
        }
        if ("equals".equals(methodName) && parameterTypes.length == 1) {
            return invoker.equals(args[0]);
        }
        return invoker.invoke(new RpcInvocation(method, args)).recreate();
    }
}

总结

从ioc获取的对象是代理对象Proxy$0
交给InvokerInvocationHandler进行处理->MockClusterInvoker -> FailoverClusterInvoker-> RegistryDirectory->invoke列表

以下是分支流程=======================


zookeeper 订阅

RegistryDirectory 实现了NotifyListener, 本身就是个监听器
调用RegistryDirectory的subscribe,registry就是ZookeeperRegistry
而订阅直接交给registry去处理, 而其中的this是RegistryDirectory

 public void subscribe(URL url) {
      setConsumerUrl(url);
      registry.subscribe(url, this);
  }

一:url和RegistryDirectory保存在subscribed中
consumer://10.118.14.24/com.test.ITestService?category=providers,configurators,routers&side=consumer…
二:ZookeeperRegistry 订阅url
调用ZookeeperRegistry.doSubscribe(final URL url, final NotifyListener listener) ;
consumer://10.118.14.24/10.118.14.24/com.test.ITestService?category=providers,configurators,routers&default.check=false&default.cluster=failfast&default.timeout=60000&dubbo=2.8.4&interface=com.insaic.itbase.service.BusinessNoGeneratorService&logger=slf4j&methods=test,save&pid=10132&revision=1.0-20191223.094125-383&side=consumer×tamp=1577323081022&version=1.0.0

  • I) 创建接口下providers、configurators、routers的路径,并且增加他们的子节点变化监听器

/dubbo/com.test.ITestService/providers
/dubbo/com.test.ITestService/configurators
/dubbo/com.test.ITestService/routers

private String[] toCategoriesPath(URL url) {
    String[] categroies;
    //接口是* ,那么categroies 就是全量
    if (Constants.ANY_VALUE.equals(url.getParameter(Constants.CATEGORY_KEY))) {
        categroies = new String[] {Constants.PROVIDERS_CATEGORY, Constants.CONSUMERS_CATEGORY, 
                Constants.ROUTERS_CATEGORY, Constants.CONFIGURATORS_CATEGORY};
    } else {
    //从url中获取category
        categroies = url.getParameter(Constants.CATEGORY_KEY, new String[] {Constants.DEFAULT_CATEGORY});
    }
    String[] paths = new String[categroies.length];
    for (int i = 0; i < categroies.length; i ++) {
       //dubbo+接口+category
        paths[i] = toServicePath(url) + Constants.PATH_SEPARATOR + categroies[i];
    }
    return paths;
}

以下是遍历这些路径path
-------> 1. 获取ChildListener子节点监听器

查看是否创建了监听器
没有,对/dubbo/com.test.ITestService/providers
/dubbo/com.test.ITestService/configurators
/dubbo/com.test.ITestService/routers
初始化监听器
子节点变化通知当前节点子节点有变化,见下一节

ConcurrentMap listeners = zkListeners.get(url);
  if (listeners == null) {
      zkListeners.putIfAbsent(url, new ConcurrentHashMap());
      listeners = zkListeners.get(url);
  }
  ChildListener zkListener = listeners.get(listener);
  if (zkListener == null) {
      listeners.putIfAbsent(listener, new ChildListener() {
          public void childChanged(String parentPath, List currentChilds) {
          	ZookeeperRegistry.this.notify(url, listener, toUrlsWithEmpty(url, parentPath, currentChilds));
          }
      });
      zkListener = listeners.get(listener);
  }

------->2. 创建持久化节点,并且增加子节点监听器
/dubbo/com.test.ITestService/providers
/dubbo/com.test.ITestService/configurators
/dubbo/com.test.ITestService/routers

 zkClient.create(path, false);
 List children = zkClient.addChildListener(path, zkListener);

------->3. 获取当前com.test.ITestService的下的providers、routes、configurators所有的子节点

在第一步遍历providers时,当前子节点是
dubbo://10.118.22.51:20710/com.test.ITestService?default.cluster=failfast&default.timeout=3000&dubbo=2.8.4&generic=false&interface=com.test.ITestService&logger=slf4j&methods=test,save&pid=3091&revision=1.0.0&side=provider×tamp=1576650287438&version=1.0.0
当configurators和routers当前没有子节点,就封装成
configurators:
empty://10.118.14.24/com.test.ITestService?&category=configurators&side=consumer×tamp=1577329888735&version=1.0.0
routers:
empty://10.118.14.24/com.test.ITestService?&category=routers&side=consumer×tamp=1577329888735&version=1.0.0

 List children = zkClient.addChildListener(path, zkListener);
 if (children != null) {
 	urls.addAll(toUrlsWithEmpty(url, path, children));
 }

//当没有子节点时,对consumer地址将协议改成empty,增加对应的category

private List toUrlsWithEmpty(URL consumer, String path, List providers) {
     List urls = toUrlsWithoutEmpty(consumer, providers);
      if (urls.isEmpty()) {
      	int i = path.lastIndexOf('/');
      	String category = i < 0 ? path : path.substring(i + 1);
      	URL empty = consumer.setProtocol(Constants.EMPTY_PROTOCOL).addParameter(Constants.CATEGORY_KEY, category);
          urls.add(empty);
      }
      return urls;
  }
  • II)通知子节点发生变化
    见下一节

订阅节点的子节点发生变化

notify(url, listener, urls);
url:消费者的url
urls: com.test.ITestService的下的providers、routes、configurators变化的子节点。
listener: RegistryDirectory

  • 场景
    1. 在订阅初始化的时候 (providers、routes、configurators全量)
    url: 当前节点
    consumer://10.118.14.24/com.test.ITestService?category=providers,configurators,routers&default.check=false&default.cluster=failfast&default.timeout=60000&dubbo=2.8.4&side=consumer×tamp=1577329888735&version=1.0.0…
    listener: RegistryDirectory
    urls:当前com.test.ITestService的下的providers、routes、configurators所有的子节点
    dubbo://10.118.22.51:20710/com.test.ITestService?default.cluster=failfast&default.timeout=3000&dubbo=2.8.4&generic=false&interface=com.test.ITestService&logger=slf4j&methods=test,save&pid=3091&revision=1.0.0&side=provider×tamp=1576650287438&version=1.0.0
    empty://10.118.14.24/com.test.ITestService?&category=configurators&side=consumer×tamp=1577329888735&version=1.0.0
    empty://10.118.14.24/com.test.ITestService?&category=routers&side=consumer×tamp=1577329888735&version=1.0.0
    2. 子节点发生变化时(providers、routes、configurators哪个有变化才调用)
 new ChildListener() {
    public void childChanged(String parentPath, List currentChilds) {
       	ZookeeperRegistry.this.notify(url, listener,
       	      toUrlsWithEmpty(url, parentPath, currentChilds));
       }
   });

providers、routes、configurators任意一个的子节点发生变化就调用notify。
url: 当前的消费者url
currentChilds是所有的子节点路径
parentPath:providers、routes、configurators

  • 源码

1. 对当前的url进行分类。按照category(providers、routes、configurators)分类, 并且放入到notified中

Map> result = new HashMap>();
    for (URL u : urls) {
        if (UrlUtils.isMatch(url, u)) {
        	String category = u.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY);
        	List categoryList = result.get(category);
        	if (categoryList == null) {
        		categoryList = new ArrayList();
        		result.put(category, categoryList);
        	}
        	categoryList.add(u);
        }
    }

2. 保存urls到文件中和properties

private void saveProperties(URL url) {
        if (file == null) {
            return;
        }
        //组装内容
        StringBuilder buf = new StringBuilder();
         Map> categoryNotified = notified.get(url);
         if (categoryNotified != null) {
             for (List us : categoryNotified.values()) {
                 for (URL u : us) {
                     if (buf.length() > 0) {
                        //空格分隔符
                         buf.append(' ');
                     }
                     buf.append(u.toFullString());
                 }
             }
         }
         //放入到properties
         properties.setProperty(url.getServiceKey(), buf.toString());
         long version = lastCacheChanged.incrementAndGet();
         //保存文件
         if (syncSaveFile) {
             doSaveProperties(version);
         } else {
             registryCacheExecutor.execute(new SaveProperties(version));
         }
    }

先创建dubbo-registry-10.118.22.55.cache.lock 空文件, 对空文件进行上锁,保存文件。然后再释放锁。

public void doSaveProperties(long version) {
  // 当前版本小于最后一次,不再保存
  if(version < lastCacheChanged.get()){
      return;
  }
  if (file == null) {
      return;
  }
  Properties newProperties = new Properties();
  // 保存之前先读取一遍,防止多个注册中心之间冲突
  InputStream in = null;
   if (file.exists()) {
       in = new FileInputStream(file);
       newProperties.load(in);
   } 
// 保存
  try {
      newProperties.putAll(properties);
      //先创建dubbo-registry-10.118.22.55.cache.lock 空文件
      File lockfile = new File(file.getAbsolutePath() + ".lock");
      if (!lockfile.exists()) {
      	lockfile.createNewFile();
      }
      //先对空文件进行上锁
      RandomAccessFile raf = new RandomAccessFile(lockfile, "rw");
      try {
          FileChannel channel = raf.getChannel();
          try {
              FileLock lock = channel.tryLock();
          	if (lock == null) {
                  throw new IOException("");
              }
          	// 保存
              try {
              	if (! file.exists()) {
                      file.createNewFile();
                  }
                  FileOutputStream outputFile = new FileOutputStream(file);  
                  try {
                      newProperties.store(outputFile, "Dubbo Registry Cache");
                  } finally {
                  	outputFile.close();
                  }
              } finally {
              	lock.release();
              }
          } finally {
              channel.close();
          }
      } finally {
          raf.close();
      }
  } catch (Throwable e) {
      if (version < lastCacheChanged.get()) {
          return;
      } else {
          registryCacheExecutor.execute(new SaveProperties(lastCacheChanged.incrementAndGet()));
      }
      logger.warn("Failed to save registry store file, cause: " + e.getMessage(), e);
  }
}

3.listener.notify(categoryList); 刷新本地的invoker
见下一节


RegistryDirectory.notify 刷新本地的invoker列表

  • 分类
    routerUrls : category是routers或者protocol是route
    configuratorUrls : category是configurators或者override是route
    invokerUrls : category是providers
List invokerUrls = new ArrayList();
List routerUrls = new ArrayList();
List configuratorUrls = new ArrayList();
for (URL url : urls) {
    String protocol = url.getProtocol();
    String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY);
    if ("routers".equals(category) || "route".equals(protocol)) {
        routerUrls.add(url);
    } else if ("configurators".equals(category)  || "override".equals(protocol)) {
        configuratorUrls.add(url);
    } else if (“”providers“”.equals(category)) {
        invokerUrls.add(url);
    } 
}
  • 获取List configurators
    对configuratorUrls 循环处理, configuratorFactory.getConfigurator(url)

根据协议来判断来做处理

override=com.alibaba.dubbo.rpc.cluster.configurator.override.OverrideConfiguratorFactory
absent=com.alibaba.dubbo.rpc.cluster.configurator.absent.AbsentConfiguratorFactory
  • 获取List routers
    Router router = routerFactory.getRouter(url);
file=com.alibaba.dubbo.rpc.cluster.router.file.FileRouterFactory
script=com.alibaba.dubbo.rpc.cluster.router.script.ScriptRouterFactory
condition=com.alibaba.dubbo.rpc.cluster.router.condition.ConditionRouterFactory
  • 刷新本地的invoker列表
    最终将生成的invoker列表保存在本地urlInvokerMap中
private void refreshInvoker(List invokerUrls){
     //....
      this.forbidden = false; // 允许访问
     //旧的invoker列表
      Map> oldUrlInvokerMap = this.urlInvokerMap; 
      if (invokerUrls.size() ==0 ){
      	return;
      }
      // 将URL列表转成Invoker列表
      Map> newUrlInvokerMap = toInvokers(invokerUrls) ;
       // 换方法名映射Invoker列表
      Map>> newMethodInvokerMap = toMethodInvokers(newUrlInvokerMap);
      //没有新的invoker,则不再处理
      if (newUrlInvokerMap == null || newUrlInvokerMap.size() == 0 ){
          return ;
      }
      
      this.methodInvokerMap = multiGroup ? toMergeMethodInvokerMap(newMethodInvokerMap) : newMethodInvokerMap;
      //保存到本地urlInvokerMap中
      this.urlInvokerMap = newUrlInvokerMap;
      try{
          //销毁未使用的invoker列表(在旧的invoker列表中,不在新的invoker列表)
          destroyUnusedInvokers(oldUrlInvokerMap,newUrlInvokerMap); 
      }catch (Exception e) {
          logger.warn("destroyUnusedInvokers error. ", e);
      }
 }

重点:获取新的invoker列表
a) 合并url参数 顺序为override >Consumer > Provider
b) 查看urlInvokerMap中是否有了,没有重新生成消费端的invoker代理对象
new InvokerDelegete(protocol.refer(serviceType, url), url, providerUrl);见下一节

c)销毁 未使用的invoker列表( in(老的invoker列表) and not in(新的invoker列表))

private Map> toInvokers(List urls) {
    Map> newUrlInvokerMap = new HashMap>();
    if(urls == null || urls.size() == 0){
        return newUrlInvokerMap;
    }
    Set keys = new HashSet();
    String queryProtocols = this.queryMap.get(Constants.PROTOCOL_KEY);
    for (URL providerUrl : urls) {
        if (Constants.EMPTY_PROTOCOL.equals(providerUrl.getProtocol())) {
            continue;
        }
        //查看协议是否支持
        if (! ExtensionLoader.getExtensionLoader(Protocol.class).hasExtension(providerUrl.getProtocol())) {
            continue;
        }
        //合并url (提供者的url和消费者的url进行合并)
        URL url = mergeUrl(providerUrl);
        
        String key = url.toFullString(); // URL参数是排序的
        if (keys.contains(key)) { // 重复URL
            continue;
        }
        keys.add(key);
        // 缓存key为没有合并消费端参数的URL,不管消费端如何合并参数,如果服务端URL发生变化,则重新refer
        Map> localUrlInvokerMap = this.urlInvokerMap; // local reference
        Invoker invoker = localUrlInvokerMap == null ? null : localUrlInvokerMap.get(key);
        if (invoker == null) { // 缓存中没有,重新refer
                //...查看是否增加disabled或者enabled
            	boolean enabled = true;
            	if (enabled) {
            		invoker = new InvokerDelegete(protocol.refer(serviceType, url), url, providerUrl);
            	}
            if (invoker != null) { // 将新的引用放入缓存
                newUrlInvokerMap.put(key, invoker);
            }
        }else {
            newUrlInvokerMap.put(key, invoker);
        }
    }
    keys.clear();
    return newUrlInvokerMap;
}

合并url参数 顺序为override > -D >Consumer > Provider

private URL mergeUrl(URL providerUrl){
   providerUrl = ClusterUtils.mergeUrl(providerUrl, queryMap); // 合并消费端参数
   //对提供者进行处理
   List localConfigurators = this.configurators; 
   if (localConfigurators != null && localConfigurators.size() > 0) {
       for (Configurator configurator : localConfigurators) {
           providerUrl = configurator.configure(providerUrl);
       }
   }
   
   providerUrl = providerUrl.addParameter(Constants.CHECK_KEY, String.valueOf(false)); // 不检查连接是否成功,总是创建Invoker!
   
   //directoryUrl 与 override 合并是在notify的最后,这里不能够处理
   this.overrideDirectoryUrl = this.overrideDirectoryUrl.addParametersIfAbsent(providerUrl.getParameters()); // 合并提供者参数        
   
   return providerUrl;
}

DubboProtocol.refer

ProtocolFilterWrapper:
过滤所有的consumer下的Filter,循环对invoker进行包装

  • 创建DubboInvoker并且保存在invokers
public  Invoker refer(Class serviceType, URL url) throws RpcException {
        optimizeSerialization(url);

        DubboInvoker invoker = new DubboInvoker(serviceType, url, getClients(url), invokers);
        invokers.add(invoker);
        return invoker;
    }
  • 初始化netty客户端
private ExchangeClient[] getClients(URL url){
     //是否共享连接
     boolean service_share_connect = false;
     int connections = url.getParameter(Constants.CONNECTIONS_KEY, 0);
     //如果connections不配置,则共享连接,否则每服务每连接
     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){
        String key = url.getAddress();
        ReferenceCountExchangeClient client = referenceClientMap.get(key);
        if ( client != null ){
            if ( !client.isClosed()){
                client.incrementAndGetCount();
                return client;
            } else {
                referenceClientMap.remove(key);
            }
        }
        ExchangeClient exchagneclient = initClient(url);
        
        client = new ReferenceCountExchangeClient(exchagneclient, ghostClientMap);
        referenceClientMap.put(key, client);
        ghostClientMap.remove(key);
        return client; 
    }

初始化客户端

/**
     * 创建新连接.
     */
    private ExchangeClient initClient(URL url) {。
        //默认开启heartbeat
        url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT));        
        
        ExchangeClient client ;
        try {
            //设置连接应该是lazy的 
            if (url.getParameter(Constants.LAZY_CONNECT_KEY, false)){
                client = new LazyConnectExchangeClient(url ,requestHandler);
            } else {
                client = Exchangers.connect(url ,requestHandler);
            }
        } catch (RemotingException e) {
            throw new RpcException("Fail to create remoting client for service(" + url
                    + "): " + e.getMessage(), e);
        }
        return client;
    }

netty客户端连接

创建客户端连接 Exchangers.connect(url ,requestHandler)
new HeaderExchangeClient(Transporters.connect(url, new DecodeHandler(new HeaderExchangeHandler(handler))))

  • HeaderExchangeClient
    初始化时,开启定时心跳
    this.channel = new HeaderExchangeChannel(client);
    定时发送心跳数据给服务端,并且超时了,重连服务端
 heatbeatTimer = scheduled.scheduleWithFixedDelay(
     new HeartBeatTask( new HeartBeatTask.ChannelProvider() {
            public Collection getChannels() {
                return Collections.singletonList( HeaderExchangeClient.this );
            }
        }, heartbeat, heartbeatTimeout),
        heartbeat, heartbeat, TimeUnit.MILLISECONDS );
  //上次读取的时间
  Long lastRead = ( Long ) channel.getAttribute(
          HeaderExchangeHandler.KEY_READ_TIMESTAMP );
 //上次写入的时间
  Long lastWrite = ( Long ) channel.getAttribute(
          HeaderExchangeHandler.KEY_WRITE_TIMESTAMP );
  //在时间内, 发送心跳信息给服务端
  if ( ( lastRead != null && now - lastRead > heartbeat )
          || ( lastWrite != null && now - lastWrite > heartbeat ) ) {
      Request req = new Request();
      req.setVersion( "2.0.0" );
      req.setTwoWay( true );
      req.setEvent( Request.HEARTBEAT_EVENT );
      channel.send( req );
  }
  //超时了,重连
  if ( lastRead != null && now - lastRead > heartbeatTimeout ) {
      if (channel instanceof Client) {
      		((Client)channel).reconnect();
      } else {
      	channel.close();
      }
  }
  • netty客户端初始化 new NettyClient

初始化

 protected void doOpen() throws Throwable {
        NettyHelper.setNettyLoggerFactory();
        bootstrap = new ClientBootstrap(channelFactory);
        // config
        // @see org.jboss.netty.channel.socket.SocketChannelConfig
        bootstrap.setOption("keepAlive", true);
        bootstrap.setOption("tcpNoDelay", true);
        bootstrap.setOption("connectTimeoutMillis", getTimeout());
        final NettyHandler nettyHandler = new NettyHandler(getUrl(), this);
        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            public ChannelPipeline getPipeline() {
                NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyClient.this);
                ChannelPipeline pipeline = Channels.pipeline();
                pipeline.addLast("decoder", adapter.getDecoder());
                pipeline.addLast("encoder", adapter.getEncoder());
                pipeline.addLast("handler", nettyHandler);
                return pipeline;
            }
        });
    }

连接
启动定时,查看是否连接,没有的话,重新连接

protected void connect() throws RemotingException {
        connectLock.lock();
        try {
            if (isConnected()) {
                return;
            }
            //启动
            initConnectStatusCheckCommand();
            doConnect();
            if (! isConnected()) {
                throw new RemotingException();
            }
            reconnect_count.set(0);
            reconnect_error_log_flag.set(false);
        } finally {
            connectLock.unlock();
        }
    }

等待服务器的响应

protected void doConnect() throws Throwable {
        long start = System.currentTimeMillis();
        ChannelFuture future = bootstrap.connect(getConnectAddress());
        try{
            //等待
            boolean ret = future.awaitUninterruptibly(getConnectTimeout(), TimeUnit.MILLISECONDS);
            //连接成功
            if (ret && future.isSuccess()) {
            
                Channel newChannel = future.getChannel();
                newChannel.setInterestOps(Channel.OP_READ_WRITE);
                try {
                    // 关闭旧的连接
                    Channel oldChannel = NettyClient.this.channel; // copy reference
                    if (oldChannel != null) {
                        try {
                            oldChannel.close();
                        } finally {
                            NettyChannel.removeChannelIfDisconnected(oldChannel);
                        }
                    }
                } finally {
                    //新连接也是关闭的,将新连接关闭
                    if (NettyClient.this.isClosed()) {
                        try {
                            newChannel.close();
                        } finally {
                            NettyClient.this.channel = null;
                            NettyChannel.removeChannelIfDisconnected(newChannel);
                        }
                    } else {
                        //赋值
                        NettyClient.this.channel = newChannel;
                    }
                }
            } else if (future.getCause() != null) {
                throw new RemotingException();
            } else {
                throw new RemotingException();
            }
        }finally{
            if (! isConnected()) {
                future.cancel();
            }
        }
    }

你可能感兴趣的:(dubbo)