你一定的收藏的Dubbo设计模式解析:对Spring配置标签扩展

一、dubbo是如何“插入”到spring框架中的

dubbo是基于Spring进行开发的,而且扩展了Spring的XML schema和注解标签,其实这里也就是整个dubbo的切入点。dubbo除去依赖其他的第三方框架外,整个框架只有一个jar包,可谓是精致。在这个jar包的NET-INF目录下有两个文件:spring.handlers和spring.schemas。其中spring.schemas中定义的就是扩展的spring配置标签,而且spring.handlers中定义的就是这些schema的处理类,就是这个类将dubbo组件“插入”到spring这个平台里的。(关于如何自定义spring配置的schema,网上资料很多,这里只简单概括)Spring在启动的时候会扫描MET-INF下所有的spring.handlers等文件,找到其中的标签处理类,并运行其init方法。

这里要插个知识点“spring的启动过程”。spring启动过程,从宏观角度来讲分为两个阶段。第一个阶段完成spring配置文件的解析,或者spring注解的解析最终将这些配置或者注解解析成BeanDefinition对象,然后进入下一个阶段,比如我们经常在spring配置文件中使用的占位符替换工作就是在这个阶段完成的。在第二个阶段中,spring用之前解析好的BeanDefinition对象来完成bean的初始化和组装工作,比如我们使用spring事务时的事务proxy就是这个阶段完成注入到service对象中的。

在这个init方法中,dubbo将自己的标签(application,module,registry,monitor,provider,consumer,protocol,service,reference)处理类注册到spring中,而这些类会完成对自己所负责的标签的解析工作,将标签最终转换为bean的描述对象BeanDefinition并返回给spring,而spring拿到这些标签对象完成bean的初始化、依赖注入(比如注入对RMI端的proxy对象)。

二、Dubbo中对Spring配置标签扩展

你一定的收藏的Dubbo设计模式解析:对Spring配置标签扩展

Java

Spring提供了可扩展Schema的支持,完成一个自定义配置一般需要以下步骤:

  • 设计配置属性和JavaBean

  • 编写XSD文件

  • 编写NamespaceHandler和BeanDefinitionParser完成解析工作

  • 编写spring.handlers和spring.schemas串联起所有部件

  • 在Bean文件中应用

dubbo中所有dubbo的标签,都统一用DubboBeanDefinitionParser进行解析,基于一对一属性映射,将XML标签解析为Bean对象。

下面我们就用dubbo为例来看如何实现对Spring配置的标签扩展。

2.1、设计配置属性和JavaBean

我们首先当然得设计好配置项,并通过JavaBean来建模。

以Dubbo的ServiceBean为例,这里定义的了dubbo每个服务的信息。

你一定的收藏的Dubbo设计模式解析:对Spring配置标签扩展

Java

2.2、编写XSD文件

XSD文件所在的位置在dubbo-config-spring项目中,如下图:

你一定的收藏的Dubbo设计模式解析:对Spring配置标签扩展

Java

以后面要用到的dubbo:service为例,:

<xsd:element name="service" type="serviceType">

<xsd:annotation>

<xsd:documentation><![CDATA[ Export service config ]]></xsd:documentation>

</xsd:annotation>

</xsd:element>

serviceType类型的定义如下:

<xsd:complexType name="serviceType">

<xsd:complexContent>

<xsd:extension base="abstractServiceType">

<xsd:choice minOccurs="0" maxOccurs="unbounded">

<xsd:element ref="method" minOccurs="0" maxOccurs="unbounded" />

<xsd:element ref="parameter" minOccurs="0" maxOccurs="unbounded" />

<xsd:element ref="beans:property" minOccurs="0" maxOccurs="unbounded" />

</xsd:choice>

<xsd:attribute name="interface" type="xsd:token" use="required">

<xsd:annotation>

<xsd:documentation></xsd:documentation>

<xsd:appinfo>

<tool:annotation>

<tool:expected-type type="java.lang.Class"/>

</tool:annotation>

</xsd:appinfo>

</xsd:annotation>

</xsd:attribute>

<xsd:attribute name="ref" type="xsd:string" use="optional">

<xsd:annotation>

<xsd:documentation></xsd:documentation>

</xsd:annotation>

</xsd:attribute>

<xsd:attribute name="class" type="xsd:string" use="optional">

<xsd:annotation>

<xsd:documentation><![CDATA[ The service implementation class name. ]]></xsd:documentation>

</xsd:annotation>

</xsd:attribute>

<xsd:attribute name="path" type="xsd:string" use="optional">

<xsd:annotation>

<xsd:documentation><![CDATA[ The service path. ]]></xsd:documentation>

</xsd:annotation>

</xsd:attribute>

<xsd:attribute name="provider" type="xsd:string" use="optional">

<xsd:annotation>

<xsd:documentation><![CDATA[ Deprecated. Replace to protocol. ]]></xsd:documentation>

</xsd:annotation>

</xsd:attribute>

<xsd:attribute name="generic" type="xsd:string" use="optional">

<xsd:annotation>

<xsd:documentation><![CDATA[ Generic service. ]]></xsd:documentation>

</xsd:annotation>

</xsd:attribute>

<xsd:anyAttribute namespace="##other" processContents="lax" />

</xsd:extension>

</xsd:complexContent>

</xsd:complexType>

比如其中的 <xsd:attribute name="ref" type="xsd:string" use="optional"> 对应的 string类型的配置项 ref。

你一定的收藏的Dubbo设计模式解析:对Spring配置标签扩展

Java

2.3、编写NamespaceHandler和BeanDefinitionParser完成解析工作

要完成解析工作,会用到NamespaceHandler和BeanDefinitionParser这两个概念。具体说来NamespaceHandler会根据schema和节点名找到某个BeanDefinitionParser,然后由BeanDefinitionParser完成具体的解析工作。因此需要分别完成NamespaceHandler和BeanDefinitionParser的实现类,Spring提供了默认实现类NamespaceHandlerSupport和AbstractSingleBeanDefinitionParser,简单的方式就是去继承这两个类。

如上图,dubbo的 NamespaceHandler 文件在 com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler 。

Handler 定义了每个配置节解析的对象,如下图代码。

DubboBeanDefinitionParser 定义也在这个目录下。

2.4、编写spring.handlers和spring.schemas串联起所有部件

上面几个步骤走下来会发现开发好的handler与xsd还没法让应用感知到,就这样放上去是没法把前面做的工作纳入体系中的,spring提供了spring.handlers和spring.schemas这两个配置文件来完成这项工作,这两个文件需要我们自己编写并放入META-INF文件夹中,这两个文件的地址必须是META-INF/spring.handlers和META-INF/spring.schemas,spring会默认去载入它们。

这两个文件,在dubbo项目中,是在dubbo-config-spring项目中,如下图:

spring.handlers 文件的内容如下:

http://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler

以上表示当使用到名为"http://code.alibabatech.com/schema/dubbo"的schema引用时,会通过com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler 来完成解析

spring.schemas 文件的内容如下:

http://code.alibabatech.com/schema/dubbo/dubbo.xsd=META-INF/dubbo.xsd

以上标示载入的xsd文件的位置。

你一定的收藏的Dubbo设计模式解析:对Spring配置标签扩展

Java

2.5、在Bean文件中应用

Dubbo的Spring的配置文件来自哪里,请参考这篇文章:

Dubbo 通过Spring 配置具体启动服务:

以dubbo-demo-provider为例,它的Spring配置文件 dubbo-demo-provider.xml内容如下:

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"

xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd

http://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsd">

<bean id="demoService" class="com.alibaba.dubbo.demo.provider.DemoServiceImpl" />

<dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService" />

</beans>

你一定的收藏的Dubbo设计模式解析:对Spring配置标签扩展

Java

其中:

  • xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" 是用来指定自定义schema,

  • xsi:schemaLocation用来指定xsd文件。

  • <dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService" /> 是一个具体的自定义配置使用实例。

  • Java学习资料获取(复制下段连接至浏览器即可) data:text/html;charset=UTF-8;base64,5oGt5Zac5L2g77yM5p625p6E5biI5a2m5Lmg576k5Y+35pivNjg2NTc5MDE0Cg==