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;
}
在这可以看出,最终是判断连接是否正常,是否可以连接