dubbo 3 (深度解剖dubbo源码)

课程链接: https://www.itwangzi.cn/2555.html

开始之前,源码基于目前Dubbo3.0.7版本;解读可能是目前文档源码有些出入,请注意版本。

Dubbo和Spring部分

Dubbo支持Spring的xml方式

基本使用和案例

其他书籍或者教程;通常会为你编写一个,HelloWorld的案例;笔者觉得,看这篇文章的读者的水平应该是达到了这个级别的;不在手写Dubbo的入门案例;Dubbo官方源码 dubbo-demo提供好了源码案例。

  1. 服务提供者编写:

    dubbo3,dubbo3的使用和原理

  2. 服务消费者编写:

    dubbo3,dubbo3的使用和原理

  3. 服务提供者、消费者主类(篇幅问题;提供链接)provider/Applicationconsumer/Application

总结:

通知配置Dubbo标签,Spring容器启动时,加载Dubbo相关的Bean,同时生成对应的接口代理,为RPC调用做好准备。

「思考:(源码阅读需要解决问题)」

  1. Dubbo如何支持Spring的?
  2. Dubbo通过代理Bean,实现Spring注入和RPC调用,那么注入哪些Bean,具体细节如何呢?

有了问题,让我们带着问题点阅读源码可能效果更好。

源码解读:

Dubbo在利用Spring可扩展的XML Schema机制时,在Spring启动时加载Dubbo自定义的标签内容(Dubbo的ximl文档[官方文档]);Dubbo的标签较多,这里依照 dubbo:service 配置(dubbo-service文档)为例;可以大体熟悉一下基本用法。

dubbo:service

dubbo:service 配置

服务提供者暴露服务配置。对应的配置类:org.apache.dubbo.config.「ServiceConfig」

属性对应URL参数类型是否必填缺省值作用描述兼容性interfaceclass「必填」 服务发现服务接口名1.0.0以上版本refobject「必填」 服务发现服务对象实现引用

「Spring可扩展的XML Schema机制」

dubbo3,dubbo3的使用和原理

「创建一个 XML Schema 文件,描述自定义的合法构建模块,也就是xsd文件」

dubbo-config/dubbo-config-spring/src/main/resources/META-INF/「dubbo.xsd」

「自定义个处理器类,并实现NamespaceHandler接口(比较容易)」

  1. 自定义接口handler实现;懂点实现 parse接口:
  • init(): NamespaceHandler被使用之前调用,完成NamespaceHandler的初始化
  • BeanDefinition parse(Element, ParserContext): 当遇到顶层元素时被调用
  • BeanDefinition decorate(Node,BeanDefinitionHandler,ParserContext): 当遇到一个属性或者嵌套元素的时候调用
@Overridepublic 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 */@Overridepublic 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;}
  1. 自定义BeanDefinitionParser实现NamespaceHandlerSupport接口;主要解析对应的BeanDefinationorg.apache.dubbo.config.spring.schema.「DubboBeanDefinitionParser」;有兴趣自行分析
  2. 注册handler和schema

    dubbo3,dubbo3的使用和原理 为了让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接口来实现该功能
  1. 对于注册Context容器;这里是Spring自定义机制;目前由于篇幅问题;多做过多的细节介绍:(请看图)

    dubbo3,dubbo3的使用和原理

Spring Bean 加载流程分析(通过 XML 方式加载)

Spring-ClassPathXmlApplicationContext源码探讨-解析XML文件_半笙彷徨的博客-CSDN博客

Spring 的annotation部分源码

基本使用和案例

dubbo3,dubbo3的使用和原理

服务接口

dubbo3,dubbo3的使用和原理

dubbo3,dubbo3的使用和原理

服务提供者:

dubbo3,dubbo3的使用和原理

dubbo3,dubbo3的使用和原理

\

源码解读

使用注解需要重点关注:@PropertySource、@DubboService、@DubboReference 就可以了

思考:

  1. Dubbo的注解都干了些啥?(这个基本看下注释和源码基本都可以明白)
  2. Dubbo如何如何让Spring识别Dubbo自定义的注解呢?
  3. 还记得之前注解对应的properties文件吗?这个也作为小问题点

源码入口 -- @EnableDubbo

  • @「EnableDubboConfig」 :加载Dubbo相关配置需要配置多个对象(ApplicationConfig、RegistryConfig、ProtocolConfig、ServiceConfig等),而这个注解的目的就是帮我们简化这些配置,只要将相应的配置项通过.properties文件交由@PropertySource注解由Spring加载到Environment中,Dubbo即可通过Environment中相应的属性与ApplicationConfig对象同名的属性进行绑定,而这个过程都是自动。
  • @「DubboComponentScan」:扫描类路径以获取将自动注册为Spring bean的注释组件。\

dubbo3,dubbo3的使用和原理

@EnableDubboConfig

@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); }

dubbo3,dubbo3的使用和原理

总结:

使用 @EnableDubbo加载Dubbo对应的共有配置Bean和postprocesser,扫描注解,加载@Service和@reference注解。更多内容启示关于Spring的框架的底层内容熟悉,Dubbo只是灵活的使用Spring的API。