Dubbo2.7源码分析-如何发布服务 (4)

重点的地方就在于插件的包裹类,StubProxyFactoryWrapper就是JavassistProxyFactory的包裹类,为什么这么说呢,因为StubProxyFactoryWrapper有一个带ProxyFactory参数的构造函数而且实现了ProxyFactory接口,具体可以看Extension的loadExtensionClasses方法源码(装饰者模式)。

Protocol

protocol对象也是一个自适应插件类,类名为Protocol$Adaptive,在上一篇文章中已有讲解。这个类会根据url的协义取得对应转义的插件类,没有的话,默认为dubbo协义,本地服务url协义为injvm,所以会加载InjvmProtocol,但是在加载InjvmProtocol并实例化后,发现InjvmProtocol还有对应的包裹类即(其实是所有Protocol的包裹类):ProtocolFilterWrapper和ProtocolListenerWrapper。ProtocolFilterWrapper类的作用是添加一些过滤器,ProtocolListenerWrapper的作用是添加ExporterListener。InjvmProtocol的export方法仅仅创建一个InjvmExporter实例,没有开启服务。

发布远程服务

如果注册url不为空,调用proxyFactory得到服务对象的代理类,然后使用protocol发布服务。由于注册url的协义是registry,在使用ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension("registry");会加载RegistryProtocol类并实例化,而且会添加其包裹类:ProtocolFilterWrapper和ProtocolListenerWrapper。而在这两个包裹类的export方法的首行,都会对registry协义进行单独处理。

RegistryProtocol if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) { return protocol.export(invoker); }

经过这两个包裹类后,最终会调用RegistryProtocol的export方法。

public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException { //发布服务 //originInvoker中包含了代理服务对象的代理类 final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker); //注册相关代码省略 //订阅相关代码省略 } private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker) { //key为发布的服务url String key = getCacheKey(originInvoker); //从map缓存中获取 ExporterChangeableWrapper<T> exporter = (ExporterChangeableWrapper<T>) bounds.get(key); //double check 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; }

最重要的是这一句:

exporter = new ExporterChangeableWrapper<T>((Exporter<T>) protocol.export(invokerDelegete), originInvoker);

其中protocol也是Protocol$Adaptive对象,而invokerDelegete的URL是服务的url.

本示例中为:

dubbo://192.168.124.1:20880/org.apache.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bind.ip=192.168.124.1&bind.port=20880&dubbo=2.0.2&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=8468&qos.port=22222&side=provider&timestamp=1536138127517

DubboProtocol

Protocol$Adaptive在解析URL的时得到dubbo,所以会加载DubboProtocol并实例化(DubboProtocol实际在前面获取默认接口时已经实例化并缓存起来了,此处取的是缓存的实例),并调用了DubboProtocol的export方法(与上面一样,在得到DubboProtocol实例后,仍然会在外面包裹一下)。

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { URL url = invoker.getUrl(); // 服务名:本例中为org.apache.dubbo.demo.DemoService:20880 String key = serviceKey(url); //exporter 控制服务打开与关闭 DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap); exporterMap.put(key, exporter); //省略发布子服务的相关代码 //打开服务 openServer(url); //优化序列化处理 optimizeSerialization(url); return exporter; }

经过层层探索,曲折迂回,终于到openServer了,进去看看。

private void openServer(URL url) { // 服务ip:端口号 String key = url.getAddress(); boolean isServer = url.getParameter(Constants.IS_SERVER_KEY, true); if (isServer) { ExchangeServer server = serverMap.get(key); if (server == null) { synchronized (this) { server = serverMap.get(key); if (server == null) { serverMap.put(key, createServer(url)); } } } else { // 服务支持重置 server.reset(url); } } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxzjg.html