1. 概述
Dubbo 服务引用,和 Dubbo 服务暴露一样,也有两种方式:
本地引用,JVM 本地调用。
远程暴露,网络远程通信。
2. 本地引用
2.1 createProxy
本地引用服务的顺序图如下:
/**
* 创建 Service 代理对象
*
* @param map 集合
* @return 代理对象
*/
@SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
private T createProxy(Map<String, String> map) {
URL tmpUrl = new URL("temp", "localhost", 0, map);
// 是否本地引用
final boolean isJvmRefer;
// injvm 属性为空,不通过该属性判断
if (isInjvm() == null) {
// 直连服务提供者,参见文档《直连提供者》https://dubbo.gitbooks.io/dubbo-user-book/demos/explicit-target.html
if (url != null && url.length() > 0) { // if a url is specified, don't do local reference
isJvmRefer = false;
// 通过 `tmpUrl` 判断,是否需要本地引用
} else if (InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl)) {
// by default, reference local service if there is
isJvmRefer = true;
// 默认不是
} else {
isJvmRefer = false;
}
// 通过 injvm 属性。
} else {
isJvmRefer = isInjvm();
}
// 本地引用
if (isJvmRefer) {
// 创建本地服务引用 URL 对象。
URL url = new URL(Constants.LOCAL_PROTOCOL, NetUtils.LOCALHOST, 0, interfaceClass.getName()).addParameters(map);
// 引用服务,返回 Invoker 对象
invoker = refprotocol.refer(interfaceClass, url);
if (logger.isInfoEnabled()) {
logger.info("Using injvm service " + interfaceClass.getName());
}
// 正常流程,一般为远程引用
} else {
// ... 省略本文暂时不分享的服务远程引用
}
// 启动时检查
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());
}
if (logger.isInfoEnabled()) {
logger.info("Refer dubbo service " + interfaceClass.getName() + " from url " + invoker.getUrl());
}
// 创建 Service 代理对象
// create service proxy
return (T) proxyFactory.getProxy(invoker);
}
2.2 isInjvmRefer
/**
* 是否本地引用
*
* @param url URL
* @return 是否
*/
public boolean isInjvmRefer(URL url) {
final boolean isJvmRefer;
String scope = url.getParameter(Constants.SCOPE_KEY);
// Since injvm protocol is configured explicitly, we don't need to set any extra flag, use normal refer process.
// 当 `protocol = injvm` 时,本身已经是 jvm 协议了,走正常流程就是了。
if (Constants.LOCAL_PROTOCOL.toString().equals(url.getProtocol())) {
isJvmRefer = false;
// 当 `scope = local` 或者 `injvm = true` 时,本地引用
} else if (Constants.SCOPE_LOCAL.equals(scope) || (url.getParameter("injvm", false))) {
// if it's declared as local reference
// 'scope=local' is equivalent to 'injvm=true', injvm will be deprecated in the future release
isJvmRefer = true;
// 当 `scope = remote` 时,远程引用
} else if (Constants.SCOPE_REMOTE.equals(scope)) {
// it's declared as remote reference
isJvmRefer = false;
// 当 `generic = true` 时,即使用泛化调用,远程引用。
} else if (url.getParameter(Constants.GENERIC_KEY, false)) {
// generic invocation is not local reference
isJvmRefer = false;
// 当本地已经有该 Exporter 时,本地引用
} else if (getExporter(exporterMap, url) != null) {
// by default, go through local reference if there's the service exposed locally
isJvmRefer = true;
// 默认,远程引用
} else {
isJvmRefer = false;
}
return isJvmRefer;
}
2.3 Protocol
涉及的 Protocol 类图如下:
2.3.1 ProtocolFilterWrapper
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
// 注册中心
if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
return protocol.refer(type, url);
}
// 引用服务,返回 Invoker 对象
// 给改 Invoker 对象,包装成带有 Filter 过滤链的 Invoker 对象.创建带有 Filter 过滤链的 Invoker 对象。
return buildInvokerChain(protocol.refer(type, url), Constants.REFERENCE_FILTER_KEY, Constants.CONSUMER);
}
2.3.2 ProtocolListenerWrapper
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
// 注册中心协议
if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
return protocol.refer(type, url);
}
// 引用服务
Invoker<T> invoker = protocol.refer(type, url);
// 获得 InvokerListener 数组
List<InvokerListener> listeners = Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(InvokerListener.class).getActivateExtension(url, Constants.INVOKER_LISTENER_KEY));
// 创建 ListenerInvokerWrapper 对象
return new ListenerInvokerWr