dubbo组成原理-service服务暴露
来源:互联网 发布:csgo 优化 编辑:程序博客网 时间:2024/05/18 18:22
继续上一篇dubbo的schema的定义,从DubboNamespaceHandler说起
这里对几个主要标签做一下说明。具体的阿里有专门出手册,手册地址为http://dubbo.io/User+Guide-zh.htm
1、<dubbo:service /> 用于服务生产者暴露服务配置
2、<dubbo:reference /> 用于服务消费者引用服务配置
3、<dubbo:protocol /> 用于服务生产者协议配置
4、<dubbo:registry /> 用于注册中心配置
5、<dubbo:method />用于方法级配置
至此用户通过dubbo的标签能完整的背spring使用
鄙人曾经不止一次看到过一句话 软件=数据+算法
容器加载的时候,通过读取用户定义的dubbo.xml配置文件,生成带了各种参数的javabean对象,然后通过复杂的算法,达到dubbo框架RPC的目的。这个设计思路和spring中的beandefinition、springmvc中的HandlerMapping 有异曲同工之妙。
service的发布
因为调用过程比较复杂,这里引用了一位大神的解释,可以给大家直观的认识
ServiceBean处理继承dubbo自己的配置抽象类以外,还实现了一系列的spring接口用来参与到spring容器的启动以及bean的创建过程中去。由于spring的实例化ServiceBean是单例模式的,在Spring的容器ApplicationContext的启动过程refresh过程中最后第二步会预先初始化单例的bean, 在bean的初始化过程会设置beanName, 设置容器applicationContext, 回调 InitializingBean的afterPropertiesSet
最后一步finishRefresh会触发ContextRefreshedEvent事件, 而ServiceBean实现了ApplicationListener接口监听了此事件, 而在之前一步实例化的ServiceBean注册了这个事件,所以ServiceBean的onApplicationEvent(ApplicationEvent event)方法被触发, 在这个方法中触发了export方法来暴露服务。
public void onApplicationEvent(ApplicationEvent event) { if (ContextRefreshedEvent.class.getName().equals(event.getClass().getName())) { if (isDelay() && ! isExported() && ! isUnexported()) { if (logger.isInfoEnabled()) { logger.info("The service ready on spring started. service: " + getInterface()); } export(); } } }跟进export()来到ServiceConfig
public synchronized void export() { if (provider != null) { if (export == null) { export = provider.getExport(); } if (delay == null) { delay = provider.getDelay(); } } if (export != null && ! export.booleanValue()) { return; } if (delay != null && delay > 0) { Thread thread = new Thread(new Runnable() { public void run() { try { Thread.sleep(delay); } catch (Throwable e) { } doExport(); } }); thread.setDaemon(true); thread.setName("DelayExportServiceThread"); thread.start(); } else { doExport(); } }
继续看doExport
protected synchronized void doExport() { if (unexported) { throw new IllegalStateException("Already unexported!"); } if (exported) { return; } exported = true; if (interfaceName == null || interfaceName.length() == 0) { throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!"); } checkDefault(); if (provider != null) { if (application == null) { application = provider.getApplication(); } if (module == null) { module = provider.getModule(); } if (registries == null) { registries = provider.getRegistries(); } if (monitor == null) { monitor = provider.getMonitor(); } if (protocols == null) { protocols = provider.getProtocols(); } } if (module != null) { if (registries == null) { registries = module.getRegistries(); } if (monitor == null) { monitor = module.getMonitor(); } } if (application != null) { if (registries == null) { registries = application.getRegistries(); } if (monitor == null) { monitor = application.getMonitor(); } } if (ref instanceof GenericService) { interfaceClass = GenericService.class; generic = true; } else { try { interfaceClass = Class.forName(interfaceName, true, Thread.currentThread() .getContextClassLoader()); } catch (ClassNotFoundException e) { throw new IllegalStateException(e.getMessage(), e); } checkInterfaceAndMethods(interfaceClass, methods); checkRef(); generic = false; } if(local !=null){ if(local=="true"){ local=interfaceName+"Local"; } Class<?> localClass; try { localClass = ClassHelper.forNameWithThreadContextClassLoader(local); } catch (ClassNotFoundException e) { throw new IllegalStateException(e.getMessage(), e); } if(!interfaceClass.isAssignableFrom(localClass)){ throw new IllegalStateException("The local implemention class " + localClass.getName() + " not implement interface " + interfaceName); } } if(stub !=null){ if(stub=="true"){ stub=interfaceName+"Stub"; } Class<?> stubClass; try { stubClass = ClassHelper.forNameWithThreadContextClassLoader(stub); } catch (ClassNotFoundException e) { throw new IllegalStateException(e.getMessage(), e); } if(!interfaceClass.isAssignableFrom(stubClass)){ throw new IllegalStateException("The stub implemention class " + stubClass.getName() + " not implement interface " + interfaceName); } } checkApplication(); checkRegistry(); checkProtocol(); appendProperties(this); checkStubAndMock(interfaceClass); if (path == null || path.length() == 0) { path = interfaceName; } doExportUrls(); }
来到doExportUrls 方法
@SuppressWarnings({ "unchecked", "rawtypes" }) private void doExportUrls() { List<URL> registryURLs = loadRegistries(true);
//因为dubbo支持多协议配置,遍历所有协议分别根据不同的协议把服务export到不同的注册中心上去 for (ProtocolConfig protocolConfig : protocols) { doExportUrlsFor1Protocol(protocolConfig, registryURLs); } }
doExportUrlsFor1Protocol方法有点多,这里就不贴出来了
protocol实现有很多
最终由RegistryProtocol提供暴露服务 export
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException { //export invoker final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker); //registry provider final Registry registry = getRegistry(originInvoker); final URL registedProviderUrl = getRegistedProviderUrl(originInvoker); registry.register(registedProviderUrl); // 订阅override数据 // FIXME 提供者订阅时,会影响同一JVM即暴露服务,又引用同一服务的的场景,因为subscribed以服务名为缓存的key,导致订阅信息覆盖。 final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registedProviderUrl); final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl); overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener); registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener); //保证每次export都返回一个新的exporter实例 return new Exporter<T>() { public Invoker<T> getInvoker() { return exporter.getInvoker(); } public void unexport() { try { exporter.unexport(); } catch (Throwable t) { logger.warn(t.getMessage(), t); } try { registry.unregister(registedProviderUrl); } catch (Throwable t) { logger.warn(t.getMessage(), t); } try { overrideListeners.remove(overrideSubscribeUrl); registry.unsubscribe(overrideSubscribeUrl, overrideSubscribeListener); } catch (Throwable t) { logger.warn(t.getMessage(), t); } } }; }
ServiceConfig.doExportUrls()执行具体的export过程
1. loadRegistries(true)
checkRegistry如果xml中没有配置注册中,从dubbo.properties中读取配置,构建RegistryConfig对象并赋值
构建注册中心URL统一数据模式集合List<registryUrl>
2. 因为dubbo支持多协议配置,遍历所有协议分别根据不同的协议把服务export到不同的注册中心上去
a) 判断是否是泛型暴露
b) 根据协议构建暴露服务的统一数据模型URL
c) 配置的了monitor加载monitor,并给URL设置MONITOR_KEY
d) 给注册中regitryUrl设置EXPORT_KEY值为前面构建的暴露服务url
e) 根据服务具体实现,实现接口以及regitryUrl从代理工厂ProxyFactory获取代理Invoker(继承于AbstractProxyInvoker),它是对具体实现的一种代理
f) Protocol.export(invoker) 暴露服务invoker
Invoker包含上一步传入的RegistryUrl, registryUrl的protocol值为registry
ProtocolListenerWrapper和ProtocolFilterWrapper对于协议为REGISTRY_PROTOCOL直接跳过,最终由RegistryProtocol处理export的过程
RegistryProtocol暴露服务过程
这里传入的Invoker是由RegistryUrl从ProxyFactory得到的Invoker
1. 从Invoker获取providerUrl,在获取cacheKey, 根据cacheKey获取本地缓存的ExporterChangeableWrapper(exporter代理,建立返回的exporter与protocol export出的exporter的对应关系), 如果存在返回。
2. 如果不存在,根据传入的 Invoker获取providerUrl, 在构建InvokerDelegete(originInvoker, providerUrl)
3. Protocol.exprot(invokerDelegete) 根据providerUrl 的协议(一般是dubbo协议)通过Protocol的设配类暴露服务,得到exporter
4. 利用providerUr导出的exporter和invoker构建对象ExporterChangeableWrapper缓存到本地
5. 由Invoker得到registryUrl。
在根据registryUrl从RegistryFactory获取Registry, 获取RegistryUrl的注册中心协议,这里我们拿zooKeeper协议为例。由dubbo的扩展机制得到的是ZookeeperRegistryFactory,得到注册器为ZookeeperRegistry
6. 由Invoker获取ProviderUrl在去除不需要在注册中心看到的字段得到registryProviderUrl
7. 注册中心(ZookeeperRegistry)注册registryProviderUrl
Registry.register(registryProviderUrl)
8. 由registryProviderUrl获取overrideSubscribeUrl,在构建OverrideListener
9. registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener) 注册中心订阅这个url, 用来当数据变化通知重新暴露, 哪zookeeper为例,暴露服务会在zookeeper生成一个节点,当节点发生变化的时候会触发overrideSubscribeListener的notify方法重新暴露服务
10. 构建并返回一个新的exporter实例
DubboProtocol暴露服务的过程
1. 从invoker获取统一数据模型url
2. 由url构建serviceKey(一般由端口,接口名,版本,group分组)
如:com.alibaba.dubbo.demo.DemoService:20880 这个是由接口和端口组成的
3. 构建DubboExporter放入本地map做缓存
4. 根据url openserver。 查找本地缓存以key为url.getAddress如果没有ExchangeServer创建。设置heartbeat时间,设置编码解码协议
根据url和ExchangeHandler 绑定server并返回(具体如何绑定专题介绍)
5. 返回DubboExporter对象
以上是比较提纲类的说明,如果理解不是很透彻的,我推荐结合另一篇从代码维度的分析。有助于消化理解
http://blog.csdn.net/jycwl/article/details/51481914
- dubbo组成原理-service服务暴露
- dubbo组成原理-service服务调用
- dubbo暴露服务过程
- Dubbo服务再暴露
- 19. Dubbo原理解析-通信层之暴露服务
- dubbo服务原始暴露流程
- Dubbo服务暴露的流程
- dubbo注解暴露服务与接收服务
- dubbo组成原理-http服务消费端如何调用
- dubbo源码阅读笔记--暴露服务时序
- Dubbo中暴露服务的过程解析
- Dubbo/Dubbox的服务暴露(一)
- dubbo原理系列1-服务端暴露过程
- dubbo源码学习(五)dubbo暴露服务的过程
- Dubbo暴露服务和引用服务的实现源码分析
- dubbo通过注解方式暴露服务和引用服务
- dubbo服务提供者暴露一个服务的详细过程
- Dubbo/Dubbox的服务暴露(三)- 服务的注册
- RGB转YUV
- python-闭包概念和append()和extend()的不同
- Charles解析https的坑
- 几种常用的下拉列表的动态加载和选中写法
- 数据结构(用C++语言描述)--第1章 绪论
- dubbo组成原理-service服务暴露
- remove-duplicates-from-sorted-list-ii
- html 如何播放背景音乐
- caffe数据层
- Linux:-bash: ***: command not found
- php不为空验证 对应jqueryvalidation验证 php表单验证
- flex布局主轴元素单独设置对齐方式
- 别让沉默埋没了未来
- 关于JSONObject to Map 数字太大被转成科学计数法的问题