dubbo服务引用,在客户端启动时可以控制是否检查依赖服务是否可用。  


dubbo官方使用手册如下:
Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能及早发现问题,默认 check="true" 。
可以通过 check="false" 关闭检查,例如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。
另外,如果你的 Spring 容器是懒加载的,或者通过 API 编程延迟引用服务,请关闭 check,否则服务临时不可用时,会抛出异常,拿到 null 引用,如果 check="false" ,总是会返回引用,当服务恢复时,能自动连上。
原文地址:http://dubbo.io/books/dubbo-user-book/demos/preflight-check.html




dubbo客户端启动服务引用的过程:


1、将服务接口转化为invoker对象
   a 通过Spring的Schemas解析自定义reference标签
   b ReferenceBean实现FactoryBean接口,提供获取远程服务对象的入口
   c ReferenceConfig 将服务接口转化为Invoker对象
     1) 本地服务接口:InjvmProtocol.refer()方法,直接new InjvmInvoker<T>()
     2)远程服务接口:RegisterProtocol.refer()
        首先:连接注册中心,Registry registry = registryFactory.getRegistry(url);
再次:往注册中心注册consumer几点 registry.register
然后:往注册中心发送订阅请求,监听providers节点,通知刷新invoker列表,将invoker存放到RegisterDirectory.urlInvokerMap中保存
最后:创建invoker对象,直接new FailoverClusterInvoker<T>


2、将invoker对象转化为客户端对象


   a 通过JDK的动态代理,将invoker转换为客户端对象 Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker))








在客户端引用服务的过程中,是如何检查服务是否可用呢?
源码如下:
在ReferenceConfig.java的createProxy()中有如下代码:


private T createProxy(Map<String, String> map) { 

//此处省略n行代码.... 

Boolean c = check; 

if (c == null && consumer != null) { 

    c = consumer.isCheck(); 

} 

if (c == null) { 

    c = true; // default true 

} 

if (c && !invoker.isAvailable()) { 

    throw new IllegalStateException("Failed to check the status of the service " + interfaceName + ". No provider available for the service " + (group == null ? "" : group + "/") + interfaceName + (version == null ? "" : ":" + version) + " from the url " + invoker.getUrl() + " to the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion()); 

} 

//此处省略n行代码.... 

 }




consumer为自定义标签对象ConsumerConfig,isCheck(),即判断配置文件中是否存在check配置项,如果没有,默认为true,即如果远程服务部存在,则抛出异常
如果配置了check="false",则进一步判断invoker.isAvailable();


invoker.isAvailable()源码如下:

RegistryDirectory.isAvailable() 



 public boolean isAvailable() { 

         if (isDestroyed()) { 

             return false; 

         } 

         Map<String, Invoker<T>> localUrlInvokerMap = urlInvokerMap; 

         if (localUrlInvokerMap != null && localUrlInvokerMap.size() > 0) { 

             for (Invoker<T> invoker : new ArrayList<Invoker<T>>(localUrlInvokerMap.values())) { 

                 if (invoker.isAvailable()) { 

                     return true; 

                 } 

             } 

         } 

         return false; 

 }




此处判断urlInvokerMap中的invoker.isAvailable();如果urlInvokerMap为空,则直接返回false


而urlInvokerMap中的数据在哪来的呢?
即上面提到的1->a->2->然后
然而urlInvokerMap中的invoker最根本的就是DubboInvoker对象,而DubboInvoker.isAvailable()源码如下:

public boolean isAvailable() { 

         if (!super.isAvailable()) 

             return false; 

         for (ExchangeClient client : clients) { 

             if (client.isConnected() && !client.hasAttribute(Constants.CHANNEL_ATTRIBUTE_READONLY_KEY)) { 

                 //cannot write == not Available ? 

                 return true; 

             } 

         } 

         return false; 

    }


 
 在这可以看出,最终是判断连接是否正常,是否可以连接