dubbo 使用了自定义标签 namespace 是http://dubbo.apache.org/schema/dubbo
spring 使用自定义标签需要到classpath目录下META-INF目录添加spring.handlers 添加namespace解析器
所以找到了org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
以上是注册每个标签的解析
所以服务暴露使用的是ServiceBean这个类(解析过程就不介绍了)
ServiceBean实现了spring的接口ApplicationListener 在容器刷新的时候会执行实现的方onApplicationEvent
服务就是在这方法里面暴露 然后就是大量的参数配置过程
export();-->doExport();-->doExportUrls();
List registryURLs = loadRegistries(true);//这儿获取的是配置的注册中心里面的对象如下:registry://localhost:2181/org.apache.dubbo.registry.RegistryService?application=sp1&dubbo=2.0.2&pid=14140®istry=zookeeper×tamp=1535640116290
这儿的protocols 是配置的暴露服务协议 有配置就是
for (ProtocolConfig protocolConfig : protocols) { doExportUrlsFor1Protocol(protocolConfig, registryURLs); }
doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List
然后获取本机ip和服务端口号 和注册配置参数得到服务的URL对象如下:
URL url = new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map); // 内容 :dubbo://169.254.38.78:20880/com.zzz.dubbodemo.api.service.DemoService?anyhost=true&application=sp1&bind.ip=127.0.0.1&bind.port=20880&dubbo=2.0.2&generic=false&interface=com.zzz.dubbodemo.api.service.DemoService&methods=add&pid=14140&side=provider×tamp=1535640387238
if (registryURLs != null && !registryURLs.isEmpty()) {
for (URL registryURL : registryURLs) {
url = url.addParameterIfAbsent(Constants.DYNAMIC_KEY, registryURL.getParameter(Constants.DYNAMIC_KEY));
URL monitorUrl = loadMonitor(registryURL);
if (monitorUrl != null) {
url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
}
if (logger.isInfoEnabled()) {
logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
}
// For providers, this is used to enable custom proxy to generate invoker
String proxy = url.getParameter(Constants.PROXY_KEY);
if (StringUtils.isNotEmpty(proxy)) {
registryURL = registryURL.addParameter(Constants.PROXY_KEY, proxy);
}
Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
}
}
循环注册中心注册每个暴露服务
registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString())//把服务URL添加到注册URL参数为export中得到一个新的URL
使用spi 获得的proxyFactory 将接口的实现类对象和接口还有 得到的新URL得到invoker(详细过程看我的另一博客) 然后在创建一个DelegateProviderMetaDataInvoker wrapperInvoker 对象将该invoker 和服务的配置信息对象包含起来
然后使用protocol.export(wrapperInvoker); 进行服务发布 并返回Exporter
由于wrapperInvoker包含的URL的是注册URL 所以protocol.export(wrapperInvoker);最终会执行到RegistryProtocol..export(wrapperInvoker) (详细了解Dubbo SPI)
//方法里面执行的这个行就是将服务绑定到netty 服务器上(默认的)该originInvoker 包含的URL 是注册中心得 URL 有个export参数对应的值 是服务的URl
final ExporterChangeableWrapper exporter = doLocalExport(originInvoker);
final Invoker invokerDelegete = new InvokerDelegete(originInvoker, getProviderUrl(originInvoker));
exporter = new ExporterChangeableWrapper((Exporter) protocol.export(invokerDelegete), originInvoker);
//getProviderUrl(originInvoker) 就是后去originInvoker 里面注册URL 参数export对应的字符串并通过URL的静态方法转化为URL对象 就拿到了提供者服务的URL
然后创建了Invoker invokerDelegete 包含了可以执行到我们具体实现类对象的invoker和提供者服务的URL
然后执行 protocol.export(invokerDelegete), originInvoker); 应为invokerDelegete 包含的URL 是提供者的服务 默认是Dubbo协议
所有经过一些wrapper会执行到DubboProtocol.export(Invoker
String key = serviceKey(url); //借口类加上本地服务器端口号例如:com.zzz.dubbodemo.api.service.DemoService:20880
DubboExporter exporter = new DubboExporter(invoker, key, exporterMap);
exporterMap.put(key, exporter);
创建DubboExporter 对象并添加缓存 将key 和exporterMap对象都给DubboExporter 是方便将自己移除缓存
openServer(url);//提供者URL 暴露出去 就是发布到服务器上已提供远程连接调用
提供者服务配置是怎么注册到服务中心的
在 RegistryProtocol..export(wrapperInvoker) 方法中一个是调用doLocalExport(originInvoker)将服务URL发布到netty服务器是上,还有一个就是将注册URL 注册到注册中心
URL providerUrl = getProviderUrl(originInvoker); //移除invoker里面url的参数"dynamic", "enabled" 的full属性
然后再删除.removeParameter(Constants.MONITOR_KEY)
.removeParameter(Constants.BIND_IP_KEY)
.removeParameter(Constants.BIND_PORT_KEY)
.removeParameter(QOS_ENABLE)
.removeParameter(QOS_PORT)
.removeParameter(ACCEPT_FOREIGN_IP);
和以点开头的参数
这些参数得到新的URL 就是registedProviderUrl
register(registryUrl, registeredProviderUrl);
Registry registry = registryFactory.getRegistry(registryUrl);
registry.register(registedProviderUrl);
registryUrl 的默认协议是zookeeper 所以registry 就是ZookeeperRegister继承于FailbackRegistry
super.register(url); //registered.add(url);将url添加到缓存当中
doRegister(url);
zkClient.create(toUrlPath(url), url.getParameter(Constants.DYNAMIC_KEY, true));
然后注册到了注册中心