dubbo源码分析第二篇-dubboxml启动-DubboNamespaceHandler结合spring完成Dubbobeandefinition加载-service注解为例

NamespaceHandlerSupport机制简介

spring允许框架开发者自定义xml标签完成beandefinition解析注册
其按照以下规范进行

1 spring.handlers
2 spring.schemas 作用:在解析XML文件时将XSD重定向到本地文件,避免在解析XML文件时需要上网下载XSD文件
3 dubbo.xsd xml文件中,对用户xml程序进行编译校验
4 自定义 DubboNamespaceHandler,覆写init和parse方法

工作机制:
1 DubboNamespaceHandler实现BeanDefinitionParser和自定义标签的绑定工作
2 在parse方法中根据xml标签寻找对应的BeanDefinitionParser完成解析
spring.handlers的作用就是使得spring容器能加载到相应的NamespaceHandler,从而完成非spring内置元素的解析 ,比如dubbo:service等等

DubboNamespaceHandler完成dubbo自定义标签解析成beandefinition过程

  • 除去annotation[在xml中开启注解功能],所有标签都是DubboBeanDefinitionParser完成解析
  • DubboBeanDefinitionParser指定了每一种xml标签的默认beanclass
  • dubbo:service 默认的beanclass是ServiceBean
public class DubboNamespaceHandler extends NamespaceHandlerSupport implements ConfigurableSourceBeanMetadataElement{
    @Override
    public void init() {
        <dubbo:application/>标签的解析器 应用
        registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
        <dubbo:registry/>标签的解析器 注册中心 zk redis等等
        registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
        registerBeanDefinitionParser("config-center", new DubboBeanDefinitionParser(ConfigCenterBean.class, true));
        registerBeanDefinitionParser("metadata-report", new DubboBeanDefinitionParser(MetadataReportConfig.class, true));
        registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
        registerBeanDefinitionParser("metrics", new DubboBeanDefinitionParser(MetricsConfig.class, true));
        registerBeanDefinitionParser("ssl", new DubboBeanDefinitionParser(SslConfig.class, true));
        <dubbo:provider/>标签的解析器 标签的解析器提供者的一些共用属性
        registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
        <dubbo:consumer/>标签的解析器 消费者的一些共用属性
        registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
        <dubbo:protocol/>标签的解析器 协议标签:dubbo rest grpc等等远程通信协议
        registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
        <dubbo:service/> 提供者
        registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
        <dubbo:reference/>标签的解析器 消费者
        registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
        registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
    }
}

构建Beandefinition

  • 通过每一个标签对应的beanclass 构建beandefinition
  • 根据xml构建PropertyValue
public class DubboBeanDefinitionParser implements BeanDefinitionParser {
    public DubboBeanDefinitionParser(Class<?> beanClass, boolean required) {
        this.beanClass = beanClass;
        this.required = required;
    }
    完成xml到beandefinition的解析
    主要设置了beanclass为内置的bean 比如服务提供者标签的ServiceBean.class
    处理了PropertyValues将来用于依赖注入
    @SuppressWarnings("unchecked")
    private static RootBeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {
        RootBeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClass(beanClass);
        beanDefinition.setLazyInit(false);
        String id = resolveAttribute(element, "id", parserContext);
        ...... 删除id生成策略 一般情况我们beandefinition的beanname 就是包名+接口名组合
        ...... 删除其他标签处理代码 
        处理 <dubbo:protocol/>
        if (ProtocolConfig.class.equals(beanClass)) {
            ...... 删除dubbo:protocol

        } else if (ServiceBean.class.equals(beanClass)) {
            根据class 解析ref
            <dubbo:service id="sa" interface="com.alibaba.dubbo.demo.DemoService"  class="com.alibaba.dubbo.demo.provider.DemoServiceImpl"> 无需设置ref
            String className = resolveAttribute(element, "class", parserContext);
            ...... 一般我们
            if (StringUtils.isNotEmpty(className)) {
                RootBeanDefinition classDefinition = new RootBeanDefinition();
                classDefinition.setBeanClass(ReflectUtils.forName(className));
                classDefinition.setLazyInit(false);
                通过这种方式,可以使用 <property /> 标签,设置 Service Bean 的属性。
                parseProperties(element.getChildNodes(), classDefinition, parserContext);
                根据class 解析ref
                beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));
            }
        }
        ...... 删除其他
        创建已解析的属性集合
        ManagedMap parameters = null;
        ...... 删除parameters构建流程  主要就是解析xml
        spring篇幅中我们提到过PropertyValues 将来在bean实例化的过程中会处理依赖注入
        if (parameters != null) {
            beanDefinition.getPropertyValues().addPropertyValue("parameters", parameters);
        }
        return beanDefinition;
    }
}

总结

  • 基于xml的形式 我们知道spring容器中构建了大量的servicebean提供者,ReferenceBean消费者
  • 没有显示提供,则这些接口的beanname为包名+接口名[一个service类既有dubbo注解也有spring注解,可以避免beanname相同]
  • 以xml为例,这些servicebean被实例化注入spring容器之后,并没有完成服务暴露
  • xml配置下,服务暴露的时机为spring refresh()调用finishRefresh,其会发布容器完成事件,DubboBootstrapApplicationListener会监听该事件,并完成服务暴露
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值