

Spring 扩展点实践:整合 Apache Dubbo(二)
source link: https://www.diguage.com/post/spring-extensions-and-dubbo-2/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Spring 扩展点实践:整合 Apache Dubbo(二)

在 Spring 扩展点实践:整合 Apache Dubbo(一) 中,D瓜哥介绍了 Dubbo 如何使用 Spring 的插件机制与 Spring 整合。限于篇幅原因,上一篇文章只介绍到了服务提供者的注册。本篇文章继续上一篇文章的主题,继续介绍 Spring 与 Dubbo 的整合过程。先来讲解一下服务消费者的生成过程。
Dubbo 生成服务消费者的过程
先来看看 XML 配置文件:
dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/spring/dubbo-consumer.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 name="demo-consumer"/>
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<dubbo:reference id="demoService" check="false" interface="org.apache.dubbo.demo.DemoService"/>
</beans>
我们先看一下 ReferenceBean
类的声明:
org.apache.dubbo.config.spring.ReferenceBean
public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean,
ApplicationContextAware, InitializingBean, DisposableBean {
// 此处省略 N 行代码
@Override
public Object getObject() {
return get();
}
// 此处省略 N 行代码
@Override
@SuppressWarnings({"unchecked"})
public void afterPropertiesSet() throws Exception {
// Initializes Dubbo's Config Beans before @Reference bean autowiring
prepareDubboConfigBeans();
// lazy init by default.
if (init == null) {
init = false;
}
// eager init if necessary.
if (shouldInit()) {
getObject();
}
}
// 此处省略 N 行代码
}
这个类实现了 FactoryBean
接口,D瓜哥在 Spring 扩展点概览及实践:FactoryBean 中对 FactoryBean
介绍。所以,请在上面的 getObject()
打个断点。
另外,这个类还实现了 InitializingBean
,D瓜哥在 Spring Bean 生命周期概述 中介绍了这个接口的用途。不了解的,请移步。
启动服务消费者程序,开始调试代码。跳过上文结束的配置解析阶段,进入到 org.apache.dubbo.config.bootstrap.DubboBootstrap#start
方法中。在这里,它调用了内部私有方法 referServices()
。但是,这个方法其实啥也没做。
上面提到,ReferenceBean
实现了 FactoryBean
接口,那么直接在 org.apache.dubbo.config.spring.ReferenceBean#getObject
方法上打断点。当调用 applicationContext.getBean(XXX)
时,就会触发断点,一路跟下去就会发现,现在 org.apache.dubbo.config.ReferenceConfig#init
方法中完成各种初始化准备工作,然后调用 org.apache.dubbo.config.ReferenceConfig#createProxy
方法创建代理。而实际代理的创建工作是由 org.apache.dubbo.rpc.proxy.AbstractProxyFactory#getProxy(Invoker<T>, boolean)
方法创建的。这样说,也不算准确。因为 AbstractProxyFactory
对象是一个子类对象,子类是通过 Dubbo 的类 SPI 加载机制来动态选择创建的。
其实,Dubbo 服务消费者实例只是一个代理,通过代理封装统一的网络请求,实现 RPC 的调用过程。
Dubbo 注解集成简述
使用 Dubbo 注解集成的入口是 org.apache.dubbo.config.spring.context.annotation.EnableDubbo
,直接上代码:
org.apache.dubbo.config.spring.context.annotation.EnableDubbo
/
* Enables Dubbo components as Spring Beans, equals
* {@link DubboComponentScan} and {@link EnableDubboConfig} combination.
* <p>
* Note : {@link EnableDubbo} must base on Spring Framework 4.2 and above
*
* @see DubboComponentScan
* @see EnableDubboConfig
* @since 2.5.8
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo {
/
* Base packages to scan for annotated @Service classes.
* <p>
* Use {@link #scanBasePackageClasses()} for a type-safe alternative to String-based
* package names.
*
* @return the base packages to scan
* @see DubboComponentScan#basePackages()
*/
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
/
* Type-safe alternative to {@link #scanBasePackages()} for specifying the packages to
* scan for annotated @Service classes. The package of each class specified will be
* scanned.
*
* @return classes from the base packages to scan
* @see DubboComponentScan#basePackageClasses
*/
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
/
* It indicates whether {@link AbstractConfig} binding to multiple Spring Beans.
*
* @return the default value is <code>true</code>
* @see EnableDubboConfig#multiple()
*/
@AliasFor(annotation = EnableDubboConfig.class, attribute = "multiple")
boolean multipleConfig() default true;
}
这个注解非常重要。一共有两点需要注意。这个方法就是注解的三个属性,分别给出了三个最重要的参数:
-
scanBasePackages
— 定义了基础扫描的包。通过@AliasFor
注解表明,这是定义@DubboComponentScan
注解的basePackages
属性。 -
scanBasePackageClasses
— 定义扫描的基础类。通过@AliasFor
注解表明,这是定义@DubboComponentScan
注解的basePackageClasses
属性。 -
multipleConfig
— 可以将AbstractConfig
(上一篇文章 Spring 扩展点实践:整合 Apache Dubbo(一) 已经做过说明) 向 Spring 中多次注册。换句话说,你可以配置多个注册中心,配置多个监控中心等等。通过@AliasFor
注解表明,这是定义@EnableDubboConfig
注解的multiple
属性,默认为true
。
接下来,让我们看看非常重要的两点内容。
@EnableDubboConfig
@EnableDubbo
注解上面加了 @EnableDubboConfig
注解,我们来看一下它的源码:
org.apache.dubbo.config.spring.context.annotation.EnableDubboConfig
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DubboConfigConfigurationRegistrar.class)
public @interface EnableDubboConfig {
/**
* It indicates whether binding to multiple Spring Beans.
*
* @return the default value is <code>true</code>
* @revised 2.5.9
*/
boolean multiple() default true;
}
这里,我们看到了熟悉的 @Import
。 DubboConfigConfigurationRegistrar
从名字就能看出应该是实现了 ImportBeanDefinitionRegistrar
接口的,打开代码,果然如此。更
在 Spring 扩展点概览及实践 和 Spring 扩展点实践:整合 MyBATIS 中有针对 @Import
和 ImportBeanDefinitionRegistrar
的详细介绍。尤其是 MyBATIS 就是使用 ImportBeanDefinitionRegistrar
来做扩展的。不懂的,请移步。
关于 DubboConfigConfigurationRegistrar
的功能,这里做个简要总结:
-
使用
@EnableConfigurationBeanBindings
注解,将配置项和对一个的 Bean 类型做一个绑定。如果multiple
属性为true
,则指出多次注册。 -
调用
org.apache.dubbo.config.spring.util.DubboBeanUtils#registerCommonBeans
方法,将公共的 Bean 注册到 Spring 中。这部分内容在 Spring 扩展点实践:整合 Apache Dubbo(一):registerCommonBeans 中已经给出了详细介绍,就不再赘述。
@DubboComponentScan
@EnableDubbo
注解上面加了 @DubboComponentScan
注解,直接上代码:
org.apache.dubbo.config.spring.context.annotation.DubboComponentScan
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {
/
* Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
* declarations e.g.: {@code @DubboComponentScan("org.my.pkg")} instead of
* {@code @DubboComponentScan(basePackages="org.my.pkg")}.
* @return the base packages to scan
*/
String[] value() default {};
/
* Base packages to scan for annotated @Service classes. {@link #value()} is an
* alias for (and mutually exclusive with) this attribute.
* <p>
* Use {@link #basePackageClasses()} for a type-safe alternative to String-based
* package names.
*
* @return the base packages to scan
*/
String[] basePackages() default {};
/*
* Type-safe alternative to {@link #basePackages()} for specifying the packages to
* scan for annotated @Service classes. The package of each class specified will be
* scanned.
*
* @return classes from the base packages to scan
*/
Class<?>[] basePackageClasses() default {};
}
又双叒叕看到了 @Import
;又双叒叕看到了 Registrar
,只是这次名字叫 DubboComponentScanRegistrar
。跟上面的一样,不再赘述。
这里总结一下 DubboComponentScanRegistrar
的功能:注册了一个类为 ServiceAnnotationBeanPostProcessor
的 BeanDefinition
,将配置项的配置信息传递给这个 BeanDefinition
实例。 ServiceAnnotationBeanPostProcessor
实现了 BeanDefinitionRegistryPostProcessor
接口,会在 Spring 的启动过程中,通过调用 postProcessBeanDefinitionRegistry
方法来注册相关的 BeanDefinition
。关于这部分内容,请移步: Spring AOP 处理流程概述。
在 Spring 启动过程中,就会调用 ServiceAnnotationBeanPostProcessor
的 postProcessBeanDefinitionRegistry
方法,在这个方法中,通过创建 DubboClassPathBeanDefinitionScanner
(继承了 ClassPathBeanDefinitionScanner
类)实例,调用 scanner.scan(packageToScan)
来注册 BeanDefinition
。另外,有一点需要指出的是: ServiceAnnotationBeanPostProcessor
目前是 @Deprecated
,后续推荐使用 ServiceClassPostProcessor
,而 ServiceAnnotationBeanPostProcessor
就是 ServiceClassPostProcessor
的子类。所以,目前处理逻辑都集中在了 ServiceClassPostProcessor
中。
关于 Apache Dubbo 与 Spring 的整合原理就全部介绍完毕了。如有什么问题,欢迎留言讨论。以后有时间,写写分布式事务解决方案 Seata 的一些原理。
Recommend
-
64
废话不多说,今天说说Spring Boot和Dubbo的整合,注册服务中心用的是Zookeeper,至于Dubbo、Zookeeper为何物我在此不再多言,不知道是什么自己去百度,本文适用于对微服务或者RPC了解的人准备的! 先介绍一下整合过程中用到...
-
39
README.md Go for Apache Dubbo 中文
-
43
README.md Go for Apache Dubbo 中文
-
74
分享嘉宾:秦金卫 火币集团 编辑整理: Hoh Xil 内容来源:大数据开源技术论坛 · 01 ...
-
66
README.md Dubbo Samples Samples for Apache Dubbo
-
14
Spring 扩展点实践:整合 Apache Dubbo(一) 2020-07-09 在上...
-
14
Dubbo是一款开源的、高性能且轻量级的Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用、智能容错和负载均衡,以及服务自动注册和发现。Dubbo最早是阿里公司内部的RPC框架,于 2011 年开源,之后迅速成为国内该类开源项目的佼佼者,2018年2...
-
7
安装ZooKeeper 我这里使用zookeeper作为服务注册中心,版本3.4.9,下载地址: http://mirrors.hust.edu.cn/apache/zookeeper/zookeeper-3.4.12/ 下载后,...
-
5
SPI 全称为 Service Provider Interface,是一种服务发现机制。当程序运行调用接口时,会根据配置文件或默认规则信息加载对应的实现类。所以在程序中并没有直接指定使用接口的哪个实现,而是在外部进行装配。要想了解 Dubbo 的设计与实现,其中 Dubbo SPI...
-
7
Apache Dubbo 云原生可观测性的探索与实践Saturday, October 07, 2023摘要:本文整理自平安壹钱包中间件资深工程师、Apache Dubbo committer宋小生在 Community Over Code 2023 大会上的分享。本篇内容主要分为五个部分:
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK