Dubbo三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
1.核心注解分析
目前Dubbo支持两种注册方式:应用级别以及接口级别的。
初学Dubbo在Web应用中的使用时经常用的注解为:@EnableDubbo
、@DubboReference
、@DubboService
三个,下面简单分析一下注解是如何发挥作用的。
@EnableDubbo
注解主要Import两个 ImportBeanDefinitionRegistrar 类型的子类:DubboComponentScanRegistrar、DubboConfigConfigurationRegistrar。但是DubboConfigConfigurationRegistrar可能是早期的版本,其功能完全可以被DubboComponentScanRegistrar取代。
DubboComponentScanRegistrar内部主要是在Spring IOC中增加类DubboSpringInitContext
、接口级别的ModuleModel
、应用级别的ApplicationModel
等相关实例。并且注册一些Dubbo框架需要使用到的核心bean,例如DubboDeployApplicationListener、DubboInfraBeanRegisterPostProcessor、DubboConfigApplicationListener等。
@DubboService
注解标识的目标类主要是被后置处理器ServiceAnnotationPostProcessor加载到Spring IOC对应的注册表中。
DubboClassPathBeanDefinitionScanner扫描指定路径下dubbo涉及的bean。如果@EnableDubbo没有显式指定路径,则默认为启动类所在的包路径,此时意味着Dubbo需要遍历应用中所有类是否为候选类,所以显示指定路径可以提升应用启动速率。
Dubbo中目标接口的多个实现类必须通过version版本号区别。针对每个候选类在Spring IOC中存在两种形式,一种是beanName + Class属性(候选类真实Class类型),另一种是 beanName:version + Class属性为ServiceBean
。最后一种形式也是后置处理器ServiceAnnotationPostProcessor类涉及的核心功能。
@DubboReference
注解是被后置处理器ReferenceAnnotationBeanPostProcessor解析的。当前后置处理器比较关注的注解如下所示分别为Reference、DubboReference。
public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBeanPostProcessor{
public ReferenceAnnotationBeanPostProcessor() {
super(DubboReference.class, Reference.class, com.alibaba.dubbo.config.annotation.Reference.class);
}
}
简单概括为:遍历Spring IOC注册表中全部的类,如果类的字段或者方法上存在Reference|DubboReference等相关注解则生成该接口对应的BeanDefinition。但是BeanDefinition中Class属性为ReferenceBean
类信息。
ReferenceBean是FactoryBean类型的类,核心就是为了创建候选类的代理类,无论是JDK动态代理还是Cglib动态代理。但是在Dubbo中代理过程是参考Spring AOP 代理流程来完成的。
2.ApplicationListener类型的监听器
Dubbo架构中主要存在三种类型的监听器:DubboConfigApplicationListener、DubboConfigBeanDefinitionConflictApplicationListener、DubboDeployApplicationListener。
- DubboDeployApplicationListener、DubboConfigBeanDefinitionConflictApplicationListener先后均触发ContextRefreshedEvent事件。
- DubboConfigApplicationListener监听器处理的事件类型是由
ReferenceAnnotationBeanPostProcessor
发布的DubboConfigInitEvent的事件。该类型的事件是在刷新IOC容器过程中触发的,也就是ContextRefreshedEvent事件触发之前发生的。
2.1.DubboConfigApplicationListener
作用:加载Dubbo涉及的相关配置。
配置文件Dubbo相关的配置信息并非由SpringBoot框架直接与实体类建立映射关系,而是利用Dubbo内置Environment加载得到jvm配置信息、系统配置信息、应用配置信息等,分别与AbstractConfig的子类进行对比,符合前提下创建对应的实例并初始化实例属性的value。
public class DubboConfigApplicationListener implements ApplicationListener<DubboConfigInitEvent>{
@Override
public void onApplicationEvent(DubboConfigInitEvent event) {
if (nullSafeEquals(applicationContext, event.getSource())) {
if (initialized.compareAndSet(false, true)) {
initDubboConfigBeans();
}
}
}
private void initDubboConfigBeans() {
// All infrastructure config beans are loaded, initialize dubbo here
moduleModel.getDeployer().prepare();//DefaultModuleDeployer
}
}
2.2.DubboDeployApplicationListener
作用:触发服务注册功能。
3.服务zk节点信息
如图所示服务在zk创建的节点信息:
其中消费端节点信息如下:
{
"name": "dubbo-consumer",
"id": "ip:20880",
"address": "ip",
"port": 20880,
"sslPort": null,
"payload": {
"@class": "org.apache.dubbo.registry.zookeeper.ZookeeperInstance",
"id": "ip:20880",
"name": "dubbo-consumer",
"metadata": {
"dubbo.endpoints": "[{\"port\":20880,\"protocol\":\"dubbo\"}]",
"dubbo.metadata-service.url-params": "{\"serialization\":\"compactedjava\",\"connections\":\"1\",\"version\":\"1.0.0\",\"dubbo\":\"2.0.2\",\"release\":\"3.0.7\",\"side\":\"provider\",\"port\":\"20880\",\"protocol\":\"dubbo\"}",
"dubbo.metadata.revision": "5adab1f6190c5e8e332960354cbd8403",
"dubbo.metadata.storage-type": "local"
}
},
"registrationTimeUTC": 1712915872096,
"serviceType": "DYNAMIC",
"uriSpec": null
}
提供端节点信息如下:
{
"name": "dubbo-provider",
"id": "ip:20880",
"address": "ip",
"port": 20880,
"sslPort": null,
"payload": {
"@class": "org.apache.dubbo.registry.zookeeper.ZookeeperInstance",
"id": "ip:20880",
"name": "dubbo-provider",
"metadata": {
"dubbo.endpoints": "[{\"port\":20880,\"protocol\":\"dubbo\"}]",
"dubbo.metadata-service.url-params": "{\"connections\":\"1\",\"version\":\"1.0.0\",\"dubbo\":\"2.0.2\",\"release\":\"3.0.7\",\"side\":\"provider\",\"port\":\"20880\",\"protocol\":\"dubbo\"}",
"dubbo.metadata.revision": "f2f3e2c0abb3b7e0e048c29b53eef957",
"dubbo.metadata.storage-type": "local"
}
},
"registrationTimeUTC": 1712461748518,
"serviceType": "DYNAMIC",
"uriSpec": null
}