本节主要阐述以下两个问题:spring
所谓的执行相关功能以下:api
接下来从使用dubbo的角度,从配置文件入手:架构
<!-- 提供方应用信息,用于计算依赖关系 --> <dubbo:application name="uop" owner="uce" /> <!-- 使用zookeeper注册中心暴露服务地址 --> <dubbo:registry protocol="zookeeper" address="zookeeper://192.168.xx.xx:2181?backup=192.168.xx.xx:2182,192.168.xx.xx:2183" /> <!--dubbox中引入Kryo和FST这两种高效Java序列化实现,来逐步取代原生dubbo中的hessian2,若是使用kryo记得添加依赖 --> <dubbo:protocol name="dubbo" serialization="kryo" port="20990" /> <!-- 定义服务提供者默认属性值 --> <dubbo:provider timeout="5000" threadpool="fixed" threads="100" accepts="1000" token="true" /> <!-- 暴露服务接口 一个服务能够用多个协议暴露,一个服务也能够注册到多个注册中心--> <!--Provider上尽可能多配置Consumer端的属性,让Provider实现者一开始就思考Provider服务特色、服务质量的问题--> <dubbo:service interface="com.yingjun.dubbox.api.UserService" ref="userService" />
上面经过dubbo提供的dubbo:application、dubbo:registry、dubbo:protocol、dubbo:provider、dubbo:service分别定义dubbo应用程序名、注册中心、协议、服务提供者参数默认值、服务提供者,这些配置后面的实现原理是什么呢?是如何启动并发挥相关做用的呢?并发
dubbo自定义标签与命名空间其实现代码在模块dubbo-config中,其核心实现以下。app
dubbo命名空间实现handler,其全路径:com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler,其源码实现以下:分布式
public class DubboNamespaceHandler extends NamespaceHandlerSupport { static { Version.checkDuplicate(DubboNamespaceHandler.class); } @Override public void init() { 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()); } }
从这里能够看出,dubbo自定义的标签主要包括:application、module、registry、monitor、provider、consumer、protocol、service、reference、annotation,其具体解析实现类主要包括:DubboBeanDefinitionParser(基于xml配置文件)、AnnotationBeanDefinitionParser(基于注解),下文会详细分析上述两个解析类的实现。ide
在dubbo-config-spring模块下的 src/main/resouce/META-INF中分别定义dubbo.xsd、spring.handlers、spring.schemas。 关于Spring如何新增命名空间与标签,在源码分析ElasticJob时已经详细介绍过,再这里就不作 过多重复,如需了解,请查看:http://www.javashuo.com/article/p-pptkrtcg-hp.html函数
咱们应该知道,Spirng的配置支持xml配置文件与注解的方式,故Dubbo也支持两种配置方式,xml与注解方式。高并发
BeanDefinitionParser:Spring定义的bean解析器,要实现自定义标签,则须要实现该接口,而后经过NamespaceHandlerSupport将Bean定义解析器注册到Spring bean解析器中。从接口中能够看出,其终极目标就是将Element element(xml节点)解析成BeanDefinition,有关于Spring BeanDefinition,请参考:https://blog.csdn.net/prestigeding/article/details/80490206 DubboBeanDefinitionParser构造函数以下:源码分析
public DubboBeanDefinitionParser(Class<!--?--> beanClass, boolean required) { this.beanClass = beanClass; this.required = required; }
beanClass:该xml标签节点最终会被Spring实例化的类名。 required:该标签的ID是否必须。 标签名称 |类名
| :-: | -: dubbo:application | ApplicationConfig dubbo:module | ModuleConfig dubbo:registry | RegistryConfig dubbo:monitor| MonitorConfig dubbo:provider | ProviderConfig dubbo:consumer| ConsumerConfig dubbo:protocol| ProtocolConfig dubbo:service| ServiceBean dubbo:reference | ReferenceBean 注,包名:com.alibaba.dubbo.config bean解析器的主要目的就是将上述标签,解析成对应的BeanDifinition,以便Spring构建上述类的实例。 本节不拷贝DubboBeanDefinitionParser根据xml定义的标签与属性转换成BeanDefinitionParser的每一行代码,本节只给出其大致关键点。 Step1:解析id属性,若是DubboBeanDefinitionParser对象的required属性为true,若是id为空,则根据以下规则构建一个id。
若是name属性不为空,则取name的值,若是已存在,则为 name + 序号,例如 name,name1,name2。
若是name属性为空,若是是dubbo:protocol标签,则取protocol属性,其余的则取interface属性,若是不为空,则取该值,但若是已存在,和name处理相同,在后面追加序号。
若是第二步还未空,则取beanClass的名称,若是已存在,则追加序号。
Step2:根据不一样的标签解析特殊属性。
Step3:解析标签,将属性与值填充到BeanDefinition的propertyValues中。最终返回BeanDefinition实例,供Spring实例化Bean。
上述已经解答了Dubbo自定义标签的解析实现,主要完成了ApplicationConfig、RegistryConfig、ServiceBean、ReferenceBean实例的初始化,那何时构建与注册中心的链接、服务提供者何时会向注册中心注册服务,服务消费者向注册中心订阅服务呢?
经过上述步骤,咱们已经知道已经成功解析注册中心、服务提供者、服务消费者的配置元信息,并将其实例化,按照咱们的思路,配置对象生成后,下一步应该是实现Dubbo服务的注册与发现机制,但代码中没法找到相关代码。
据我目前所掌握的知识,Spring在对象实例化,通常有两种方式来对Bean作一些定制化处理。
浏览表格中全部Bean的声明,发现了两个类很是特殊:
ServiceBean(服务提供者)与ReferenceBean(服务消费者)比较特殊,实现了Spring与Bean生命周期相关的接口。
看到这里,难免有一点小激动,彷佛已经摸到Dubbo服务注册与发现机制(Dubbo服务提供者、Dubbo服务消费者、注册中心的启动流程入口点了,下一步就是分析ServiceBean、ReferenceBean的实现原理,试图揭开Dubbo服务注册与发现机制,该部份内容将在下一篇中详细分析。
注解配置方式的解析入口类:AnnotationBeanDefinitionParser,也是基于Spring注解解析逻辑,这部分在将在将来《Spring系列进阶篇-源码分析注解解析实现原理》中详细分析,目前暂未深究,读者朋友们,若是有兴趣,能够以AnnotationBeanDefinitionParser为入口,进行进一步的分析。
本节就讲解到这里了,下一篇将重点分析ServiceBean(服务提供者启动流程)。
做者介绍:丁威,《RocketMQ技术内幕》做者,RocketMQ 社区布道师,公众号:中间件兴趣圈 维护者,目前已陆续发表源码分析Java集合、Java 并发包(JUC)、Netty、Mycat、Dubbo、RocketMQ、Mybatis等源码专栏。能够点击连接:中间件知识星球,一块儿探讨高并发、分布式服务架构,交流源码。