最后再回到 JavassistProxyFactory 类的 getInvoker 方法,可以看到它实际返回的是 AbstractProxyInvoker 对象,当调用 AbstractProxyInvoker 类的 doInvoke() 方法时,实际调用的是 wrapper 类的 invokeMethod() 方法!这个知识点十分重要!在我们讲 Dubbo 远程调用的时候会再次回顾这块内容!
exporter 对象的构建 Exporter<?> exporter = protocol.export(wrapperInvoker);再来看看后半句代码。这里最后会调用 RegistryProtocol 类的 export() 方法,若对此有疑问请看系列文章第一篇:【Dubbo源码阅读系列】之 Dubbo SPI 机制,后文不再赘述。 直接看看 RegistryProtocol 的 export() 方法:
RegistryProtocol.export() public class RegistryProtocol implements Protocol { public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException { //export invoker final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker); URL registryUrl = getRegistryUrl(originInvoker); //registry provider final Registry registry = getRegistry(originInvoker); final URL registeredProviderUrl = getRegisteredProviderUrl(originInvoker); //to judge to delay publish whether or not boolean register = registeredProviderUrl.getParameter("register", true); ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registeredProviderUrl); if (register) { register(registryUrl, registeredProviderUrl); ProviderConsumerRegTable.getProviderWrapper(originInvoker).setReg(true); } // Subscribe the override data // FIXME When the provider subscribes, it will affect the scene : a certain JVM exposes the service and call the same service. Because the subscribed is cached key with the name of the service, it causes the subscription information to cover. final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registeredProviderUrl); final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker); overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener); registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener); //Ensure that a new exporter instance is returned every time export return new DestroyableExporter<T>(exporter, originInvoker, overrideSubscribeUrl, registeredProviderUrl); } }RegistryProtocol.export() 方法非常重要!!可以说是服务远程暴露的核心了。废话不多说,让我们逐行来看看吧!
doLocalExport() private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker) { // 获取 providerUrl ,取 originInvoker url.parameters 键值对中 key 为 export 的值 String key = getCacheKey(originInvoker); ExporterChangeableWrapper<T> exporter = (ExporterChangeableWrapper<T>) bounds.get(key); if (exporter == null) { synchronized (bounds) { exporter = (ExporterChangeableWrapper<T>) bounds.get(key); if (exporter == null) { final Invoker<?> invokerDelegete = new InvokerDelegete<T>(originInvoker, getProviderUrl(originInvoker)); exporter = new ExporterChangeableWrapper<T>((Exporter<T>) protocol.export(invokerDelegete), originInvoker); bounds.put(key, exporter); } } } return exporter; }先来看看 doLocalExport() 方法做了什么:
从 getCacheKey() 方法中获取到的,键 export 对应的 value 在如下代码中被添加到 url 的 parameters 集合中。然后我们在这里取出对应的值。
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));尝试从 bounds 缓存中取对应当前键 key 的 exporter。
如果缓存为 null,新建 exporter 并返回。这里的 protocl 对象为 Protocol$Adaptive。不难分析最后执行的实际是 DubboProtocol 的 export() 方法。
总结一下:doLocalExport() 用 ExporterChangeableWrapper 代理类包装了 protocol.export() 方法返回的 exporter 对象,最后放到了 bounds 集合中缓存。
DubboPrtocol.export() DubboProtocol.java public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { URL url = invoker.getUrl(); // export service. String key = serviceKey(url); DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap); exporterMap.put(key, exporter); //export an stub service for dispatching event Boolean isStubSupportEvent = url.getParameter(Constants.STUB_EVENT_KEY, Constants.DEFAULT_STUB_EVENT); Boolean isCallbackservice = url.getParameter(Constants.IS_CALLBACK_SERVICE, false); if (isStubSupportEvent && !isCallbackservice) { String stubServiceMethods = url.getParameter(Constants.STUB_EVENT_METHODS_KEY); if (stubServiceMethods == null || stubServiceMethods.length() == 0) { if (logger.isWarnEnabled()) { logger.warn(new IllegalStateException("consumer [" + url.getParameter(Constants.INTERFACE_KEY) + "], has set stubproxy support event ,but no stub methods founded.")); } } else { stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods); } } openServer(url); optimizeSerialization(url); return exporter; }接着上文继续看 DubboProtocol.export() 方法是如何创建 exporter 对象的:
调用 serviceKey() 方法构建服务的 key 值,最后的获得的 key 值形式类似 group/path:version:port
新建 DubboExporter
openServer(url),此时的 url 为 RegistryProtocol 传递过来的 providerUrl,openServer() 用途我们在后文分析;