转载

Spring 扩展点实践:整合 Apache Dubbo

在上一篇文章 Spring 扩展点概览及实践 中介绍了 Spring 内部存在的扩展点。 Spring 扩展点实践:整合 MyBATIS 中,D瓜哥带大家了解了一下 MyBATIS 如何利用 Spring 的扩展点实现了与 Spring 的完美整合。现在,学以致用,我们继续来分析一下 Spring 与 Apache Dubbo 的整合流程。

示例程序

Apache Dubbo 仓库中就有很完整的示例。D瓜哥直接拿来使用就不再搭建示例程序了。

首先,需要启动一个 ZooKeeper 实例。查看 Dubbo 的依赖可以看出,最新版代码依赖的 ZooKeeper 是 3.4.13 版。所以,为了最好的兼容性,就要选用 3.4.X 版的 ZooKeeper 服务器。D瓜哥直接使用 Docker 启动 ZooKeeper 了。命令如下:

docker run --rm --name zookeeper -d -p 2181:2181 zookeeper:3.4.14

这次我们使用 Apache Dubbo 的 dubbo-demo/dubbo-demo-xml 示例。

第二步,启动服务提供者程序,找到 DUBBO/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/java/org/apache/dubbo/demo/provider/Application.java ,运行该类。

第三步,运行服务消费者程序,找到 DUBBO/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/java/org/apache/dubbo/demo/consumer/Application.java ,运行该类。

如果没有任何错误,则在终端可以看到 result: async result 输出。

在开始正餐之前,D瓜哥先给大家来个开胃菜。

Spring 插件机制简介

不知道大家有没有想过一个问题:Spring 框架是如何支持越来越多的功能的?

在D瓜哥了解到 Spring 的插件机制后,非常叹服 Spring 精巧的设计和灵活的扩展性。闲言少叙,好戏上演。

这里再问大家一个问题:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           https://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/aop
                           https://www.springframework.org/schema/aop/spring-aop.xsd
                           http://www.springframework.org/schema/context
                           https://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/tx
                           https://www.springframework.org/schema/tx/spring-tx.xsd
                           http://dubbo.apache.org/schema/dubbo
                           http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

	<context:annotation-config/>

	<tx:annotation-driven proxy-target-class="true" order="0"/>

	<aop:config>
		<aop:advisor pointcut="execution(* ..ITestBean.(..))" advice-ref="txAdvice"/>
	</aop:config>

	<tx:advice id="txAdvice">
		<tx:attributes>
			<tx:method name="get*" timeout="5" read-only="true"/>
			<tx:method name="set*"/>
			<tx:method name="exceptional"/>
		</tx:attributes>
	</tx:advice>


	<bean id="transactionManager" class="org.springframework.transaction.testfixture.CallCountingTransactionManager"/>

	<bean id="testBean" class="org.springframework.beans.testfixture.beans.TestBean"/>

</beans>

这是非常典型的 Spring XML 配置。相信大家都见过。大家有没有想过,Spring 是怎么处理这些不同的命名空间的?如果说 AOP、事务这些是 Spring 内置支持的功能,这样配置,Spring 可以正确解析。但是,Dubbo 的配置又是怎么回事?

要回答这个问题,就要说起 Spring 的插件机制。在 Spring 的插件机制面前,无论是 Dubbo,还是 Spring 的 AOP、事务管理都是人人平等的。它们都是依靠 Spring 的插件机制插拔在 Spring 核心模块之上的。

这篇文章不是专门介绍 Spring 插件机制的。这里抛砖引玉,对 Spring 插件机制做个简介。后续有机会再做更详细的介绍和说明。

要利用 Spring 插件机制,需要做这么几个事情:

  1. 定义自己业务的类。

  2. 编写 XSD 文件,定义自己的 XML 格式,将文件放在 src/main/resources/META-INF 目录下。

  3. 针对每一个标签,定义一个实现 BeanDefinitionParser 接口的类,在 parse 方法中完成对这个标签的解析工作,将其转化成一个 BeanDefinition 对象。

  4. 继承 NamespaceHandlerSupport 类,在 init() 方法中,使用 registerBeanDefinitionParser() 将标签名称和上面写的 BeanDefinitionParser 实现类之间建起起对应关系。

  5. 创建 src/main/resources/META-INF/spring.schemas 文件,在其中写上: http/://www.diguage.com/schema/diguage/diguage.xsd=META-INF/diguage.xsd ,为该 XSD 文件定义唯一的命名空间。

  6. 创建 src/main/resources/META-INF/spring.handlers 文件,在其中写上: http/://www.diguage.com/schema/diguage=com.diguage.schema.DiguageNamespaceHandler

完成上面这些步骤就相当于制作了一个 Spring 插件。这样就可以在 Spring XML 配置文件中,像使用 AOP、事务管理那样来使用这个新插件了。

仔细想想,Spring 的插件机制还是挺简单的:首先,定义一个 Bean 类,然后设计 XSD 文件来对 Bean 的属性进行定义。用户在使用插件时,使用 XML 来定义 Bean 类的属性值,再自定义的 BeanDefinitionParser 实现类将 XML 中的配置信息解析出来,封装在 BeanDefinition (关于 BeanDefinition 的更多信息,请移步 深入剖析 Spring 核心数据结构:BeanDefinition )。到了 BeanDefinition 之后,Spring 在内部就可以统一处理了。

下面,结合代理来具体说明一下 Apache Dubbo 的实现过程。

Apache Dubbo 插件机制解析

Apache Dubbo 最初就说通过 Spring 插件机制实现了它与 Spring 的整合过程。

  1. 相关业务类有 ApplicationConfigModuleConfigRegistryConfigConfigCenterBeanMetadataReportConfigMonitorConfigMetricsConfigSslConfigProviderConfigConsumerConfigProtocolConfigServiceBeanReferenceBean 。这些类的命名也都非常讲究,见文知意,与 Dubbo 常见配置可以说是一一对应。

  2. Dubbo 的 XSD 定义在 dubbo.xsd ,懂 XSD 的朋友应该都能看出来,这个文件就是规范上一步提到的类的属性的。

  3. DubboBeanDefinitionParser 实现了 BeanDefinitionParser 接口,用于解析 XML 配置,并将其“翻译”为第一步中那些类的对象。另外,还注册了一个 AnnotationBeanDefinitionParser ,用来处理 annotation 标签,进而用来处理注解。

  4. DubboNamespaceHandler 继承了 NamespaceHandlerSupport ,并且在 init() 方法中完成了对上述类的 DubboBeanDefinitionParser 注册。

  5. dubbo-config/dubbo-config-spring/src/main/resources/META-INF 目录下,有 spring.schemas 文件和 spring.handlers 文件。

下面以调试跟进的方式来分析整个处理过程。

Apache Dubbo 配置解析

这里使用示例程序中的配置文件:

dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/resources/spring/dubbo-provider.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://dubbo.apache.org/schema/dubbo
                           http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <dubbo:application metadata-type="remote" name="demo-provider"/>

    <dubbo:metadata-report address="zookeeper://127.0.0.1:2181"/>

    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>

    <dubbo:protocol name="dubbo"/>

    <bean id="demoService" class="org.apache.dubbo.demo.provider.DemoServiceImpl"/>

    <dubbo:service interface="org.apache.dubbo.demo.DemoService" ref="demoService"/>
</beans>

org.apache.dubbo.config.spring.schema.DubboNamespaceHandler#init 方法、 org.apache.dubbo.config.spring.schema.DubboNamespaceHandler#parse 方法 和 org.apache.dubbo.config.spring.schema.DubboBeanDefinitionParser#parse(Element, ParserContext) 方法打断点开始调试。注意:这三个方法都是重载方法,很容易识别。

先写这些,明天继续…

原文  https://www.diguage.com/post/spring-extensions-and-dubbo/
正文到此结束
Loading...