Dubbo原理之服务暴露

大致过程为:
1 xml加载为对应的BeanDefinition。配置xml,然后找到spring.handlers对应的类DubboNamespaceHandler,调用其init()方法将dubbo对应的标识,通过DubboBeanDefinitionParser.parse()初始化为spring的beanDefinition,用于后续的对象反射初始化。
2 暴露服务。通过ServiceBean继承spring-bean的三个对应接口,然后分别调用其方法,最后调用到export()方法,初始化成以dubbo://开头的完整url,然后是使用JavassistProxyFactory为invoker通过makeWrapper()方法生成字节码,然后通过反射创建返回实例, 然后创建一个nettyServer然后绑定好端口。
3 服务注册。在RegistryProtocol的export()方法注册服务。
 
1 dubbo如何将xml加载成BeanDefination
第一步:配置xml如下:
 
Dubbo原理之服务暴露
 
 
由图可知dubbo在xml中加入了对应的schema,并通过"http://code.alibabatech.com/schema/dubbo"搜索可得如下:
 
Dubbo原理之服务暴露
 
 
对应的找到上面的DubboNamespaceHandler,然后打开DubboNamespaceHandler如下:
 
Dubbo原理之服务暴露
 
 
由上可见是通过DubboBeanDefinitionParser来解析dubbo标签,并通过registerBeanDefinitionParser将标签与对应的DubboBeanDefinitionParser对象绑定在map中 如下:
 
Dubbo原理之服务暴露
 
 
调用玩init之后,会调用DubboBeanDefinitionParser的parse方法,将xml解析成Spring的beanDefinition。
 
Dubbo原理之服务暴露
 
注:当前BeanDefinition保存了类名、scope、属性、构造函数参数列表、依赖bean、是否单利/懒加载等。后面可通过该beanDefinition使用反射创建对象。
其中xml里面有些属性如ref、class的加载顺序可在xml中分析如下:
 
Dubbo原理之服务暴露
 
Dubbo原理之服务暴露
 
注:如果class、ref同时存在,则ref的会覆盖class,因为ref在后续的执行中。
 

2 ServiceBean如何暴露服务
点进ServiceBean.java这个类,继承了ApplicationContextAware、ApplicationListener、InitializingBean通过顺序执行其对应方法setApplicationContext()、afterPropertiesSet()、onApplicationEvent(),如下:
首先执行setApplicationContext()设置上下文相关信息,然后执行afterPropertiesSet()方法如下:
 
Dubbo原理之服务暴露
 
注:BeanFactoryUtils.beansOfTypeIncludingAncestors从上下文中获取了这个class的bean,然后在afterPropertiesSet()最后看到调用了export()  ---暴露服务的关键
 
然后执行onApplicationEvent()防止前面export()方法执行失败,如下:
 
Dubbo原理之服务暴露
 
接下来研究下ServiceConfig.export()是怎么暴露方法的?点进去export方法发现可设置延时,但是最后都会执行到doExport方法,如下:
 
Dubbo原理之服务暴露
 
然后追到ServiceConfig.doExport()可知,然后checkDefault()初始化provider变量、checkApplication初始化application变量等。。
 
Dubbo原理之服务暴露
 
然后看到doExport()最下面的doExportUrls()方法,如下:
 
Dubbo原理之服务暴露
 
通过loadRegisteries()将变量的地址拼接上appliation、registryconfig参数,然后通过遍历potocols,再把module、provider的参数也拼上去,最后变成完整的url,如下格式
registry://xxx.xxx.xx:2181/xxx.xxx.xxService?k1=v1&k2=v2............
dubbo://xxx.xxx.xx:2181/xxx.xxx.xxService?anyhost=true&application=xxx-bank&default.accepts=100&default.dispatcher=all&default.threadpool=fixed&default.threads=100&default.timeout=30000&dubbo=bank&interface=xxx.service.BankSettlementFacade&methods=update,listAvailableBankAccount,listHasCutOffTimeBankChannel,listPage,getByBankBankChannelCode,getById,listAvailableBankSettlementInfo,create&pid=13816&retries=0&revision=bank&serverApplicationName=gw-service-bank&side=provider×tamp=1547015081759
注:1 第一次生成的是registry://xxx。然后遍历后就生成了dubbo://xxx,拼接了完整的参数。包含所有上下文信息(如所有方法名、版本号、序列化方法等)
       2 loadRegisteries()从System.getProperty("dubbo.registry.address");获取注册中心地址。
 
然后继续看遍历过程调的doExportUrlsForProtocol()后面,如下:
 
Dubbo原理之服务暴露
 
上面生成好一个代理好的serviceBean,然后放在exporter下,最后exporter又被放在serviceBean的一个exporters下。创建的nettySever也被放在serviceBean下。然后最后会在doExport()下面处理如下:
// ProviderModel 表示服务提供者模型,此对象中存储了与服务提供者相关的信息。 
// 比如服务的配置信息,服务实例等。每个被导出的服务对应一个 ProviderModel。 
// ApplicationModel 持有所有的 ProviderModel。 
ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), this, ref); 
ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel);
 
 
参考文章: