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

简单叙述一下获取url的过程,url通过map组装参数和对应的值,参数有ApplicationConfig和RegistryConfig对象的属性以及path、dubbo、timestamp、pid、protocol、registry。

本示例applicationConfig是:

registryURL
registryConfig是:

最终map组装结果是:

url parameters

最后得到registryURL是:

registry://224.5.6.7:1234/org.apache.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.2&pid=4892&qos.port=22222&registry=multicast&timestamp=1536112339884

然后调用doExportUrlsFor1Protocol方法发布服务,此方法开始部分是构造发布的服务URL,然后再发布url。

服务URL
URL包括以下几部分:服务端还是客户端标识Dubbo版本,时间戳,Pid,服务的方法名tokenApplicationConfig,MoudleConfig,ProviderConfig,ProtocolConfig,*MethodConfig对象的相关属性等。
例如本示例的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=8004&qos.port=22222&side=provider&timestamp=1536114090787

我们来着重看一下在构造URL过程中port的获取过程。

//protocolConfig是配置的<dubbo:protocol />生成的对象 //name是protocol的name,本示例为"dubbo" //map保存了url的键值对 Integer port = this.findConfigedPorts(protocolConfig, name, map);

findConfigedPorts顾名思义是查找配置的port,从哪查呢,先从系统环境变量查,如果没找到,再查找名字为name的protocol协义。

private Integer findConfigedPorts(ProtocolConfig protocolConfig, String name, Map<String, String> map) { Integer portToBind = null; // 从环境变量从查找绑定的port String port = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_BIND); portToBind = parsePort(port); // 如果没有从环境变量从查到,则从名称为name的protocol查找 if (portToBind == null) { portToBind = protocolConfig.getPort(); if (provider != null && (portToBind == null || portToBind == 0)) { portToBind = provider.getPort(); } //这一句是关键,示例中name值是"dubbo",所以会实例化DubboProtocol,得到默认的port:20880 final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort(); if (portToBind == null || portToBind == 0) { portToBind = defaultPort; } if (portToBind == null || portToBind <= 0) { portToBind = getRandomPort(name); if (portToBind == null || portToBind < 0) { portToBind = getAvailablePort(defaultPort); putRandomPort(name, portToBind); } logger.warn("Use random available port(" + portToBind + ") for protocol " + name); } } //保存port到map中,以便后面url使用 map.put(Constants.BIND_PORT_KEY, String.valueOf(portToBind)); // 从环境变量中查找注册的port,如果没有找到,则等于绑定的Port. String portToRegistryStr = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_REGISTRY); Integer portToRegistry = parsePort(portToRegistryStr); if (portToRegistry == null) { portToRegistry = portToBind; } return portToRegistry; }

有人或许有疑问,ServiceConfig在实例化时,不是已经加载过Protocol了吗?为什么还要使用ExtensionLoader加载一次呢?

final int defaultPort =ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort();

答: ServiceConfig实例化时,加载的Protocol是自适应的Protocol,是动态生成的,类名是Protocol$Adaptive(见Dubbo源码分析-SPI的应用中有分析)。而这里获取Port时加载的也是Protocol类,但指名了具体加载的是哪个Protocol(本示例是名称为dubbo的Protocol,即DubboProtocol,此类默认的端口是20880)。

发布URL 发布本地服务

调用ServiceConfig类的exportLocal(URL url)发布本地服务。

private void exportLocal(URL url) { if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) { //本地服务url URL local = URL.valueOf(url.toFullString()) .setProtocol(Constants.LOCAL_PROTOCOL) .setHost(LOCALHOST) .setPort(0); ServiceClassHolder.getInstance().pushServiceClass(getServiceClass(ref)); Exporter<?> exporter = protocol.export( proxyFactory.getInvoker(ref, (Class) interfaceClass, local)); exporters.add(exporter); logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry"); } }

本示例的本地服务 url是:

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

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