dubbo底层源码详解(Dubbo3深度剖析)
dubbo底层源码详解(Dubbo3深度剖析)服务提供者暴露服务配置。对应的配置类:org.apache.dubbo.config.「ServiceConfig」dubbo:service 配置「思考:(源码阅读需要解决问题)」有了问题,让我们带着问题点阅读源码可能效果更好。Dubbo在利用Spring可扩展的XML Schema机制时,在Spring启动时加载Dubbo自定义的标签内容(Dubbo的ximl文档[官方文档]);Dubbo的标签较多,这里依照 dubbo:service 配置(dubbo-service文档)为例;可以大体熟悉一下基本用法。
课程链接:https://www.itwangzi.cn/2555.html
开始之前,源码基于目前Dubbo3.0.7版本;解读可能是目前文档源码有些出入,请注意版本。
dubbo和Spring部分Dubbo支持Spring的xml方式基本使用和案例其他书籍或者教程;通常会为你编写一个,HelloWorld的案例;笔者觉得,看这篇文章的读者的水平应该是达到了这个级别的;不在手写Dubbo的入门案例;Dubbo官方源码 dubbo-demo提供好了源码案例。
- 服务提供者编写:
- 服务消费者编写:
- 服务提供者、消费者主类
(篇幅问题;提供链接)
provider/Application
consumer/Application
通知配置Dubbo标签,Spring容器启动时,加载Dubbo相关的Bean,同时生成对应的接口代理,为RPC调用做好准备。
「思考:(源码阅读需要解决问题)」
- Dubbo如何支持Spring的?
- Dubbo通过代理Bean,实现Spring注入和RPC调用,那么注入哪些Bean,具体细节如何呢?
有了问题,让我们带着问题点阅读源码可能效果更好。
源码解读:Dubbo在利用Spring可扩展的XML Schema机制时,在Spring启动时加载Dubbo自定义的标签内容(Dubbo的ximl文档[官方文档]);Dubbo的标签较多,这里依照 dubbo:service 配置(dubbo-service文档)为例;可以大体熟悉一下基本用法。
dubbo:servicedubbo:service 配置
服务提供者暴露服务配置。对应的配置类:org.apache.dubbo.config.「ServiceConfig」
属性对应URL参数类型是否必填缺省值作用描述兼容性interfaceclass「必填」
服务发现服务接口名1.0.0以上版本ref
object「必填」
服务发现服务对象实现引用
「Spring可扩展的XML Schema机制」
「创建一个 XML Schema 文件,描述自定义的合法构建模块,也就是xsd文件」
dubbo-config/dubbo-config-spring/src/main/resources/META-INF/「dubbo.xsd」
「自定义个处理器类,并实现NamespaceHandler接口(比较容易)」
- 自定义接口handler实现;懂点实现 parse接口:
- init(): NamespaceHandler被使用之前调用,完成NamespaceHandler的初始化
- BeanDefinition parse(Element ParserContext): 当遇到顶层元素时被调用
- BeanDefinition decorate(Node BeanDefinitionHandler ParserContext): 当遇到一个属性或者嵌套元素的时候调用
public void init() {
// spring在解析Dubbo.xml标签时,调用模板init方法初始化用于解析Dubbo自定义的XML标签注解的解析器(DubboBeanDefinitionParser)
registerBeanDefinitionParser("application" new DubboBeanDefinitionParser(ApplicationConfig.class));
registerBeanDefinitionParser("module" new DubboBeanDefinitionParser(ModuleConfig.class));
registerBeanDefinitionParser("Registry" new DubboBeanDefinitionParser(RegistryConfig.class));
registerBeanDefinitionParser("config-center" new DubboBeanDefinitionParser(ConfigCenterBean.class));
registerBeanDefinitionParser("metadata-report" new DubboBeanDefinitionParser(MetadataReportConfig.class));
registerBeanDefinitionParser("monitor" new DubboBeanDefinitionParser(MonitorConfig.class));
registerBeanDefinitionParser("metrics" new DubboBeanDefinitionParser(MetricsConfig.class));
registerBeanDefinitionParser("ssl" new DubboBeanDefinitionParser(SslConfig.class));
registerBeanDefinitionParser("provider" new DubboBeanDefinitionParser(ProviderConfig.class));
registerBeanDefinitionParser("consumer" new DubboBeanDefinitionParser(ConsumerConfig.class));
registerBeanDefinitionParser("Protocol" new DubboBeanDefinitionParser(ProtocolConfig.class));
registerBeanDefinitionParser("service" new DubboBeanDefinitionParser(ServiceBean.class));
registerBeanDefinitionParser("reference" new DubboBeanDefinitionParser(ReferenceBean.class));
registerBeanDefinitionParser("annotation" new AnnotationBeanDefinitionParser());
}
/**
* Override {@link NamespaceHandlerSupport#parse(Element ParserContext)} method
*
* @param element {@link Element}
* @param parserContext {@link ParserContext}
* @return
* @since 2.7.5
*/
@Override
public BeanDefinition parse(Element element ParserContext parserContext) {
BeanDefinitionRegistry registry = parserContext.getRegistry();
registerAnnotationConfigProcessors(registry);
// initialize dubbo beans
DubboSpringInitializer.initialize(parserContext.getRegistry());
/**
* 重点调用Spring的org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse方法;
* 就是对应init内部方法的DubboBeanDefinitionParser{@link DubboBeanDefinitionParser#parse(Element ParserContext)}#parse方法
*/
BeanDefinition beanDefinition = super.parse(element parserContext);
setSource(beanDefinition);
return beanDefinition;
}
- 自定义BeanDefinitionParser实现NamespaceHandlerSupport接口;主要解析对应的BeanDefination
org.apache.dubbo.config.spring.schema.「DubboBeanDefinitionParser」;有兴趣自行分析 - 注册handler和schema
为了让Spring在解析xml的时候能够感知到我们的自定义元素,我们需要把namespaceHandler和xsd文件放到2个指定的配置文件中,这2个文件都位于META-INF目录中
Spring通过XML解析程序将其解析为DOM树,通过NamespaceHandler指定对应的Namespace的BeanDefinitionParser将其转换成BeanDefinition。再通过Spring自身的功能对BeanDefinition实例化对象。
在期间,Spring还会加载两项资料:
- 「META-INF/spring.handlers」
指定NamespaceHandler(实现org.springframework.beans.factory.xml.NamespaceHandler)接口,或使用org.springframework.beans.factory.xml.NamespaceHandlerSupport的子类。 - 「META-INF/spring.schemas」
在解析XML文件时将XSD重定向到本地文件,避免在解析XML文件时需要上网下载XSD文件。通过现实org.xml.sax.EntityResolver接口来实现该功能
- 对于注册Context容器;这里是Spring自定义机制;目前由于篇幅问题;多做过多的细节介绍:(请看图)
Spring Bean 加载流程分析(通过 XML 方式加载)
Spring-ClassPathXmlApplicationContext源码探讨-解析XML文件_半笙彷徨的博客-CSDN博客
Spring 的annotation部分源码基本使用和案例服务接口
服务提供者:
\
源码解读使用注解需要重点关注:@PropertySource、@DubboService、@DubboReference 就可以了
思考:
- Dubbo的注解都干了些啥?(这个基本看下注释和源码基本都可以明白)
- Dubbo如何如何让Spring识别Dubbo自定义的注解呢?
- 还记得之前注解对应的properties文件吗?这个也作为小问题点
- @「EnableDubboConfig」 :加载Dubbo相关配置
需要配置多个对象(ApplicationConfig、RegistryConfig、ProtocolConfig、ServiceConfig等),而这个注解的目的就是帮我们简化这些配置,只要将相应的配置项通过.properties文件交由@PropertySource注解由Spring加载到Environment中,Dubbo即可通过Environment中相应的属性与ApplicationConfig对象同名的属性进行绑定,而这个过程都是自动。 - @「DubboComponentScan」:扫描类路径以获取将自动注册为Spring bean的注释组件。\
@Import(DubboConfigConfigurationRegistrar.class)注解导入;用于解析和加载通用的Bean :
// ImportBeanDefinitionRegistrar 注解 配合 @Import使用public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata BeanDefinitionRegistry registry) {
// initialize dubbo beans(Spring从初始化,加载Dubbo相关的Bean)
DubboSpringInitializer.initialize(registry);
// Config beans creating from props have move to ConfigManager
// AnnotationAttributes attributes = AnnotationAttributes.fromMap(
// importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));
//
// Boolean multiple = attributes.getBoolean("multiple");
//
// // Single Config Bindings
// registerBeans(registry DubboConfigConfiguration.Single.class);
//
// if (multiple) { // Since 2.6.6 https://github.com/apache/dubbo/issues/3193
// registerBeans(registry DubboConfigConfiguration.Multiple.class);
// }
}
}
DubboBeanUtils#registerCommonBeans /**
* Register the common beans
*
* @param registry {@link BeanDefinitionRegistry}
* @see ReferenceAnnotationBeanPostProcessor
* @see DubboConfigDefaultPropertyValueBeanPostProcessor
* @see DubboConfigAliasPostProcessor
* @see DubboBootstrapApplicationListener
*/
static void registerCommonBeans(BeanDefinitionRegistry registry) {
registerInfrastructureBean(registry ServicePackagesHolder.BEAN_NAME ServicePackagesHolder.class);
registerInfrastructureBean(registry ReferenceBeanManager.BEAN_NAME ReferenceBeanManager.class);
// Since 2.5.7 Register @Reference Annotation Bean Processor as an infrastructure Bean
registerInfrastructureBean(registry ReferenceAnnotationBeanPostProcessor.BEAN_NAME
ReferenceAnnotationBeanPostProcessor.class);
// TODO Whether DubboConfigAliasPostProcessor can be removed ?
// Since 2.7.4 [Feature] https://github.com/apache/dubbo/issues/5093
registerInfrastructureBean(registry DubboConfigAliasPostProcessor.BEAN_NAME
DubboConfigAliasPostProcessor.class);
// Since 2.7.4 Register DubboBootstrapApplicationListener as an infrastructure Bean
// registerInfrastructureBean(registry DubboBootstrapApplicationListener.BEAN_NAME
// DubboBootstrapApplicationListener.class);
// register ApplicationListeners
registerInfrastructureBean(registry DubboDeployApplicationListener.class.getName() DubboDeployApplicationListener.class);
registerInfrastructureBean(registry DubboConfigApplicationListener.class.getName() DubboConfigApplicationListener.class);
// Since 2.7.6 Register DubboConfigDefaultPropertyValueBeanPostProcessor as an infrastructure Bean
registerInfrastructureBean(registry DubboConfigDefaultPropertyValueBeanPostProcessor.BEAN_NAME
DubboConfigDefaultPropertyValueBeanPostProcessor.class);
// Dubbo config initializer
registerInfrastructureBean(registry DubboConfigBeanInitializer.BEAN_NAME DubboConfigBeanInitializer.class);
// register infra bean if not exists later
registerInfrastructureBean(registry DubboInfraBeanRegisterPostProcessor.BEAN_NAME DubboInfraBeanRegisterPostProcessor.class);
}
总结:
使用 @EnableDubbo加载Dubbo对应的共有配置Bean和postprocesser,扫描注解,加载@Service和@reference注解。更多内容启示关于Spring的框架的底层内容熟悉,Dubbo只是灵活的使用Spring的API。