快捷搜索:  汽车  科技

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提供好了源码案例。

  1. 服务提供者编写:

    dubbo底层源码详解(Dubbo3深度剖析)(1)

  2. 服务消费者编写:

    dubbo底层源码详解(Dubbo3深度剖析)(2)

  3. 服务提供者、消费者主类
    (篇幅问题;提供链接)
    provider/Application
    consumer/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参数类型是否必填缺省值作用描述兼容性interface
class「必填」
服务发现服务接口名1.0.0以上版本ref
object「必填」
服务发现服务对象实现引用

「Spring可扩展的XML Schema机制」

dubbo底层源码详解(Dubbo3深度剖析)(3)

「创建一个 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): 当遇到一个属性或者嵌套元素的时候调用
@Override
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;
}
  1. 自定义BeanDefinitionParser实现NamespaceHandlerSupport接口;主要解析对应的BeanDefination
    org.apache.dubbo.config.spring.schema.「DubboBeanDefinitionParser」;有兴趣自行分析
  2. 注册handler和schema

    dubbo底层源码详解(Dubbo3深度剖析)(4)


    为了让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自定义机制;目前由于篇幅问题;多做过多的细节介绍:(请看图)

    dubbo底层源码详解(Dubbo3深度剖析)(5)

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

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

Spring 的annotation部分源码基本使用和案例

dubbo底层源码详解(Dubbo3深度剖析)(6)

服务接口

dubbo底层源码详解(Dubbo3深度剖析)(7)

dubbo底层源码详解(Dubbo3深度剖析)(8)

服务提供者:

dubbo底层源码详解(Dubbo3深度剖析)(9)

dubbo底层源码详解(Dubbo3深度剖析)(10)

\

源码解读

使用注解需要重点关注:@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的注释组件。\

dubbo底层源码详解(Dubbo3深度剖析)(11)

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

dubbo底层源码详解(Dubbo3深度剖析)(12)

总结:

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

猜您喜欢: