精华内容
下载资源
问答
  • dubbo配置scheme文件

    千次下载 热门讨论 2014-10-14 15:43:24
    dubbo配置scheme文件
  • dubbo的配置解析过程集成了spring框架的能力,本文介绍dubbo的几种配置方式,配置项,配置方式优先级,配置项属性优先级,以及从xml配置方式解读dubbo解析dubbo标签的源码,深入理解dubbo配置解析的详细细节和设计...

    一、Dubbo配置

    Dubbo框架直接集成了spring的能力,利用spring配置文件扩展出自定义配置文件解析方式。dubbo定义了自己的配置约束文件,dubbo-config/dubbo-config-spring/src/main/resources/dubbo.xsd,用以解析dubbo标签。

    1.dubbo配置文件覆盖策略

    dubbo常用的三种配置方式:xml配置,注解,属性文件(properties或yaml)。除了这三种常用的配置方式,还可以通过JVM参数,代码编码的方式配置。
    dubbo配置的默认覆盖策略有以下几点原则:

    • -D传递给JVM参数优先级最高,比如:-Dubbo.protocol.port=20880
    • 代码或xml配置优先级次高,也就是spring的xml文件中的dubbo标签
    • properties或yaml配置文件优先级最低,如dubbo.properties,一般可用作配置默认值。只有xml文件没有定义时,dubbo.properties文件的属性才会生效。

    2.dubbo 标签

    (1) dubbo标签配置项列表

    dubbo默认已实现的dubbo标签如下:

    标签 用途 解释
    <dubbo:service/> 服务配置 用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心
    <dubbo:reference/> 引用配置 用于创建一个远程服务代理,一个引用可以指向多个注册中心
    <dubbo:protocol/> 协议配置 用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受
    <dubbo:application/> 应用配置 用于配置当前应用信息,不管该应用是提供者还是消费者
    <dubbo:module/> 模块配置 用于配置当前模块信息,可选
    <dubbo:registry/> 注册中心配置 用于配置连接注册中心相关信息
    <dubbo:monitor/> 监控中心配置 用于配置连接监控中心相关信息,可选
    <dubbo:provider/> 提供方配置 当 ProtocolConfig 和 ServiceConfig 某属性没有配置时,采用此缺省值,可选
    <dubbo:consumer/> 消费方配置 当 ReferenceConfig 某属性没有配置时,采用此缺省值,可选
    <dubbo:method/> 方法配置 用于 ServiceConfig 和 ReferenceConfig 指定方法级的配置信息
    <dubbo:argument/> 参数配置 用于指定方法参数配置
    另外,dubbo标签支持自定义参数扩展,如:
    <dubbo:protocol name="jms">
        <dubbo:parameter key="queue" value="your_queue" />
    </dubbo:protocol>
    

    (2) dubbo标签优先级

    这些标签在dubbo应用启动时会通过DubboBeanDefinitionParser进行解析,将 XML 标签解析为 Bean 对象。这些bean对象有一定的层级关系,多个标签的相同属性可能会被覆盖,这个优先级的原则是:

    • 方法级优先,接口级次之,全局配置再次之
    • 如果级别一样,则消费方优先,提供方次之

    其中,服务方的标签的属性可以通过URL参数的形式传给消费方。Dubbo的参数传递方式统一用URL的形式来实现,注意不是jdk的URL,是dubbo自己定义的URL
    以timeout属性为例,用官网的一张图展示dubbo标签的优先级:
    在这里插入图片描述
    其中<dubbo:provider>标签属性可以理解为<dubbo:service>标签属性的默认值,同样,后者会覆盖前者,<dubbo:consumer>标签属性可以理解为<dubbo:reference>标签属性的默认值,后者覆盖前者。
    当使用缺省值时,是延迟初始化的,只有引用被注入到其它 Bean,或被 getBean() 获取,才会初始化。如果需要饥饿加载,即没有人引用也立即生成动态代理,可以配置init属性,比如:<dubbo:reference ... init="true" />

    二、dubbo配置解析原理

    下面通过源码介绍配置解析的详细细节。这里只设计最常用的xml配置的方式。

    1.dubbo配置解析的代码流程

    (1) 配置解析入口

    dubbo应用在启动时,首先进行spring配置文件的解析,当遇到dubbo名称空间时,会回调 DubboNamespaceHandler,该类主要把不同的标签关联到解析实现类中。
    该类继承了spring的NamespaceHandlerSupport类,重写init方法,做主要逻辑,代码如下:

    	@Override
        public void init() {
            registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
            registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
            registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
            registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
            registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
            registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
            registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
            registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
            registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
            registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
        }
    

    可以看到registerBeanDefinitionParser方法将遇到的dubbo标签名交给DubboBeanDefinitionParser类来处理,具体的解析逻辑就在DubboBeanDefinitionParserparse方法里,DubboBeanDefinitionParser的parse方法是配置解析的核心代码,该方法代码比较长,主要做了以下几件事情:

    • 生成并检查spring bean定义BeanDefinition
    • 解析具体的标签,注入到BeanDefinition 中
    • 两种方式解析标签的属性,注入到标签对应bean中

    下面分段来读一下这个parse方法:
    关键节点添加了注释:

    (2) 生成spring bean定义并检查

    private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {
    		//生成spring的bean定义,指定beanCLass交给spring反射创建实例
            RootBeanDefinition beanDefinition = new RootBeanDefinition();
            beanDefinition.setBeanClass(beanClass);
            beanDefinition.setLazyInit(false);
            String id = element.getAttribute("id");
            //确保spring容器没有重复的bean
            if ((id == null || id.length() == 0) && required) {
            	//取name属性值作为bean id
                String generatedBeanName = element.getAttribute("name");
                if (generatedBeanName == null || generatedBeanName.length() == 0) {
                	//如果protocol标签没有指定name,则默认用“dubbo”做bean id
                    if (ProtocolConfig.class.equals(beanClass)) {
                        generatedBeanName = "dubbo";
                    } else {//其他标签没有指定name属性,则默认使用interface属性作为bean id
                        generatedBeanName = element.getAttribute("interface");
                    }
                }
                if (generatedBeanName == null || generatedBeanName.length() == 0) {
                    generatedBeanName = beanClass.getName();
                }
                id = generatedBeanName;
                int counter = 2;
                //检查重复bean,如果有重复,则生成唯一bean id
                while (parserContext.getRegistry().containsBeanDefinition(id)) {
                    id = generatedBeanName + (counter++);
                }
            }
            if (id != null && id.length() > 0) {
                if (parserContext.getRegistry().containsBeanDefinition(id)) {
                    throw new IllegalStateException("Duplicate spring bean id " + id);
                }
                //每次解析都会向Spring注册新的BeanDefiniton,后续会追加属性
                parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
                beanDefinition.getPropertyValues().addPropertyValue("id", id);
            }
            /*未完待续*/
    

    前面这一块主要负责把标签解析成对应的bean定义,并注册到spring上下文中,同时保证spring容器中相同id的bean不会被覆盖。

    (3) 具体dubbo标签的解析

    下面来看具体的像<dubbo:service><dubbo:provider><dubbo:consumer>等标签的解析,这些标签都会解析成xxxConfig类型,最后实例化,其中<dubbo:service><dubbo:reference>标签是xxxBean类型,其实也是xxxConfig的子类,因为这两个标签代表具体的服务暴露和服务消费,父类抽象了一些逻辑出来。

    		/*上接*/
    		if (ProtocolConfig.class.equals(beanClass)) {
                for (String name : parserContext.getRegistry().getBeanDefinitionNames()) {
                    BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(name);
                    PropertyValue property = definition.getPropertyValues().getPropertyValue("protocol");
                    if (property != null) {
                        Object value = property.getValue();
                        if (value instanceof ProtocolConfig && id.equals(((ProtocolConfig) value).getName())) {
                            definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id));
                        }
                    }
                }
            } else if (ServiceBean.class.equals(beanClass)) {
            	//拿到service标签的class属性,也就是服务接口的全限定名
                String className = element.getAttribute("class");
                if (className != null && className.length() > 0) {
                    RootBeanDefinition classDefinition = new RootBeanDefinition();
                    //反射生成实例,挂在bean定义上
                    classDefinition.setBeanClass(ReflectUtils.forName(className));
                    classDefinition.setLazyInit(false);
                    //该方法主要解析标签中的属性,通过键值对的方式提取出来放到bean定义中,spring会自动注入这些属性。
                    parseProperties(element.getChildNodes(), classDefinition);
                    beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));
                }
            } else if (ProviderConfig.class.equals(beanClass)) {
                parseNested(element, parserContext, ServiceBean.class, true, "service", "provider", id, beanDefinition);
            } else if (ConsumerConfig.class.equals(beanClass)) {
                parseNested(element, parserContext, ReferenceBean.class, false, "reference", "consumer", id, beanDefinition);
            }
    

    在解析<dubbo:provider><dubbo:consumer>时,复用了parseNested方法,主要逻辑是处理内部嵌套标签,因为<dubbo:provider>标签是可以内部嵌套<dubbo:service>标签的,同理<dubbo:consumer>标签可以内部嵌套<dubbo:reference>标签,该方法逻辑定义了内部标签会持有外部标签的对象,这种设计可以使得内部标签可以直接持有外部标签的属性。也就是<dubbo:service>可以获取<dubbo:provider>的属性作为缺省值。

    (3) 标签属性的解析和注入

    标签的属性提取方式主要分为以下两种:

    • 查找配置对象的get,set,is前缀的方法,并通过反射调用方法名与属性名相同的方法,进行注入。
    • 如果没有属性名找不到对应的get,set,is前缀方法,则当做parameters参数存储,它是一Map对象。

    以上两种方式最终都会将属性作为URL参数存储到dubbo框架的URL中。

    DubboBeanDefinitionParserparse方法里,关于属性解析的这片代码过于细节,由于篇幅过长,这里就粘贴出来了。可以自行查看源码。

    以上三步操作完成后,parse方法返回一个已经属性注入的spring框架的Beandefinition对象。如果属性是引用对象,dubbo默认会创建RuntimeBeanReference类型进行注入,运行时由spring来注入引用对象。
    其实这里dubbo只做了属性提取,从标签提取到BeanDefinition,运行时注入和转换都又spring来完成。

    2.Dubbo标签承载对象继承关系

    最后,放上一张dubbo标签承载对象的继承关系图:
    在这里插入图片描述


    展开全文
  • dubbo配置详解

    2017-11-16 13:47:17
    一、dubbo常用配置 dubbo:service/> 服务配置,用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心。 eg、dubbo:service ref="demoService" interface=...
    

    dubbo配置文件详解

    一、dubbo常用配置

    复制代码

    <dubbo:service/>服务配置,用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心。

    eg<dubbo:serviceref="demoService" interface="com.unj.dubbotest.provider.DemoService"/>

     

    <dubbo:reference/>引用服务配置,用于创建一个远程服务代理,一个引用可以指向多个注册中心。

    eg<dubbo:referenceid="demoService" interface="com.unj.dubbotest.provider.DemoService"/>

     

    <dubbo:protocol/>协议配置,用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受。

    eg<dubbo:protocolname="dubbo" port="20880"/>

     

    <dubbo:application/>应用配置,用于配置当前应用信息,不管该应用是提供者还是消费者。

    eg<dubbo:applicationname="xixi_provider"/>

       <dubbo:applicationname="hehe_consumer"/>

     

    <dubbo:module/>模块配置,用于配置当前模块信息,可选。

    <dubbo:registry/>注册中心配置,用于配置连接注册中心相关信息。

    eg<dubbo:registryaddress="zookeeper://192.168.2.249:2181"/>

     

    <dubbo:monitor/>监控中心配置,用于配置连接监控中心相关信息,可选。

    <dubbo:provider/>提供方的缺省值,当ProtocolConfigServiceConfig某属性没有配置时,采用此缺省值,可选。

    <dubbo:consumer/>消费方缺省配置,当ReferenceConfig某属性没有配置时,采用此缺省值,可选。

    <dubbo:method/>方法配置,用于ServiceConfigReferenceConfig指定方法级的配置信息。

    <dubbo:argument/>用于指定方法参数配置。



    二、服务调用超时设置
    http://images2015.cnblogs.com/blog/270324/201609/270324-20160910122039394-1078905366.png
    上图中以timeout为例,显示了配置的查找顺序,其它retries, loadbalance, actives也类似。
    方法级的配置优先级高于接口级,consumer的优先级高于provider。同时,在本地参数配置还存在一层优先级  


    其中,服务提供方配置,通过URL经由注册中心传递给消费方。
    建议由服务提供方设置超时,因为一个方法需要执行多长时间,服务提供方更清楚,如果一个消费方同时引用多个服务,就不需要关心每个服务的超时设置。
    理论上ReferenceConfig的非服务标识配置,在ConsumerConfigServiceConfig, ProviderConfig均可以缺省配置。




    三、启动时检查
    Dubbo
    缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止Spring初始化完成,以便上线时,能及早发现问题,默认check=true


    如果你的Spring容器是懒加载的,或者通过API编程延迟引用服务,请关闭check,否则服务临时不可用时,会抛出异常,拿到null引用,如果check=false,总是会返回引用,当服务恢复时,能自动连上。


    可以通过check="false"关闭检查,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。


    复制代码


    1、关闭某个服务的启动时检查:(没有提供者时报错)


    <dubbo:referenceinterface="com.foo.BarService" check="false"/>


     


    2、关闭所有服务的启动时检查:(没有提供者时报错) 写在定义服务消费者一方


    <dubbo:consumercheck="false"/>


     


    3、关闭注册中心启动时检查:(注册订阅失败时报错)


    <dubbo:registrycheck="false"/>


    复制代码


    引用缺省是延迟初始化的,只有引用被注入到其它Bean,或被getBean()获取,才会初始化。
    如果需要饥饿加载,即没有人引用也立即生成动态代理,可以配置:


    <dubbo:referenceinterface="com.foo.BarService" init="true"/>


    四、订阅
    1
    、问题
    为方便开发测试,经常会在线下共用一个所有服务可用的注册中心,这时,如果一个正在开发中的服务提供者注册,可能会影响消费者不能正常运行。


    2、解决方案
    可以让服务提供者开发方,只订阅服务(开发的服务可能依赖其它服务),而不注册正在开发的服务,通过直连测试正在开发的服务。


    禁用注册配置:


    <dubbo:registryaddress="10.20.153.10:9090" register="false"/>


    或者:


    <dubbo:registryaddress="10.20.153.10:9090?register=false"/>


    五、回声测试(测试服务是否可用)
    回声测试用于检测服务是否可用,回声测试按照正常请求流程执行,能够测试整个调用是否通畅,可用于监控。
    所有服务自动实现EchoService接口,只需将任意服务引用强制转型为EchoService,即可使用。


    eg<dubbo:referenceid="memberService" interface="com.xxx.MemberService"/>


     


    MemberService memberService =ctx.getBean("memberService"); //远程服务引用


    EchoService echoService = (EchoService)memberService; //强制转型为EchoService


    String status =echoService.$echo("OK"); //回声测试可用性


    assert(status.equals("OK"))


    六、延迟连接
    延迟连接,用于减少长连接数,当有调用发起时,再创建长连接。
    只对使用长连接的dubbo协议生效。


    <dubbo:protocolname="dubbo" lazy="true"/>


    七、令牌验证
    防止消费者绕过注册中心访问提供者,在注册中心控制权限,以决定要不要下发令牌给消费者,注册中心可灵活改变授权方式,而不需修改或升级提供者


    复制代码


    1、全局设置开启令牌验证:


    <!--随机token令牌,使用UUID生成-->


    <dubbo:providerinterface="com.foo.BarService" token="true"/>


     


    <!--固定token令牌,相当于密码-->


    <dubbo:providerinterface="com.foo.BarService" token="123456"/>


     


    2、服务级别设置开启令牌验证:


    <!--随机token令牌,使用UUID生成-->


    <dubbo:serviceinterface="com.foo.BarService" token="true"/>


     


    <!--固定token令牌,相当于密码-->


    <dubbo:serviceinterface="com.foo.BarService" token="123456"/>


     


    3、协议级别设置开启令牌验证:


    <!--随机token令牌,使用UUID生成-->


    <dubbo:protocolname="dubbo" token="true"/>


     


    <!--固定token令牌,相当于密码-->


    <dubbo:protocolname="dubbo" token="123456"/>


    复制代码


    八、日志适配
    缺省自动查找:log4jslf4jjcljdk


    可以通过以下方式配置日志输出策略:dubbo:applicationlogger="log4j"/>


    访问日志:
    如果你想记录每一次请求信息,可开启访问日志,类似于apache的访问日志。此日志量比较大,请注意磁盘容量。


    将访问日志输出到当前应用的log4j日志:


    <dubbo:protocolaccesslog="true"/>


    将访问日志输出到指定文件:


    <dubbo:protocolaccesslog="http://10.20.160.198/wiki/display/dubbo/foo/bar.log"/>


    九、配置Dubbo缓存文件


    配置方法如下:


    <dubbo:registryfile=”${user.home}/output/dubbo.cache” />


    注意:
    文件的路径,应用可以根据需要调整,保证这个文件不会在发布过程中被清除。如果有多个应用进程注意不要使用同一个文件,避免内容被覆盖。


    这个文件会缓存:
    注册中心的列表
    服务提供者列表


    有了这项配置后,当应用重启过程中,Dubbo注册中心不可用时则应用会从这个缓存文件读取服务提供者列表的信息,进一步保证应用可靠性。







    展开全文
  • Dubbo配置文件简单说明

    千次阅读 2018-11-09 11:35:25
    Dubbo配置说明 xml配置 所有配置项可分为三大类: 服务发现:该配置项用于服务的注册与发现,目的是让消费方找到提供方。 服务治理:该配置项用于治理服务间的关系,或者为开发测试提供便利条件。 性能调优:...

    Dubbo采用全spring配置方式,透明化接入应用,对应用没有任何API侵入,只需用Spring加载Dubbo的配置即可,Dubbo基于Spring的Schema扩展进行加载。

    Dubbo配置说明

    xml配置

    所有配置项可分为三大类:

    • 服务发现:该配置项用于服务的注册与发现,目的是让消费方找到提供方。
    • 服务治理:该配置项用于治理服务间的关系,或者为开发测试提供便利条件。
    • 性能调优:该配置项用于调优性能,不同的选项对性能会产生影响。
      所有配置最终都将转化为URL表示,并由服务提供方生成,经注册中心传递给消费方,各属性对应URL的参数,URL格式如下:protocol://username:password@host:port/path?key=value&key=value

    服务提供方<dubbo:service />

    • interface
      dubbo服务暴露的接口全路径,例如:<dubbo:service interface="cn.test.edu.service.ItemService" />

    • ref
      dubbo服务暴露接口的实现类,例如:
      <bean id="itemServiceImpl" class="cn.test.edu.service.impl.ItemServiceImpl" /> <dubbo:service interface="cn.test.edu.service.ItemService" ref="itemServiceImpl" />
      不过在spring框架中,采用IOC与DI,所以一般service实现类,都通过@Service注解,交由spring容器帮我们创建bean对象,默认id为类的首字母小写。所以可以直接写成,例如:
      <dubbo:service interface="cn.test.edu.service.ItemService" ref="itemServiceImpl" />

    • timeout
      远程调用服务超时时间,如果客户端服务端都配置了以客户端为准,客户端没有配置以服务端为准,单位毫秒,默认1000

    服务消费方<dubbo:reference />

    • interface
      服务提供者接口全路径,例如:
    <dubbo:reference interface="cn.test.edu.service.ItemService" />
    
    • id
      服务消费方引用Bean的id,一般为接口类的首字母小写。

    服务提供方<protocol />

    • id
      协议BeanId,可以在<dubbo:service protoco="" />中引用此id,如果id不填,缺省和name属性值相同,重复则在name后加序号

    • name
      协议名称,支持常见的传输协议:Dubbo、RMI、Hessain、WebService、Http等

    • port
      dubbo协议缺省端口为20880,RMI协议缺省端口为1099,http和hessian协议缺省端口为80,如果配置为-1 或者配置port,则会分配一个没有被占用的端口。Dubbo 2.4.0+,分配的端口在协议缺省端口的基础上增长,确保端口端可控

    注册中心配置<dubbo:registry />

    • id
      注册中心引用BeanId,可以在<dubbo:service registry="" /><dubbo:reference registy="" />中引用此id ,1.0.16以上版本

    • protocol
      注册中心地址协议,支持dubbo,http,local三种协议,分别表示,dubbo地址,http地址,本地注册中心

    • address
      注册中心服务器地址,如果地址没有端口缺省值为9090,同一集群内的多个地址用逗号分隔,如:ip:port,ip:port 不同集群的注册中心,请配置多个

    应用配置<dubbo:application />

    • name
      必填项,当前应用名称,用于注册中心计算应用间依赖关系,注意:消费者和提供者应用名不要一样,此参数不是匹配条件
    展开全文
  • DUBBO配置规则详解

    万次阅读 多人点赞 2015-03-03 16:25:31
    DUBBO配置规则详解 欢迎加入DUBBO交流群:259566260 研究DUBBO也已经大半年了,对它的大部分源码进行了分析,以及对它的内部机制有了比较深入的了解,以及各个模块的实现。DUBBO包含很多内容,如果想了解DUBBO第一...

    DUBBO配置规则详解

    欢迎加入DUBBO交流群:259566260

    研究DUBBO也已经大半年了,对它的大部分源码进行了分析,以及对它的内部机制有了比较深入的了解,以及各个模块的实现。DUBBO包含很多内容,如果想了解DUBBO第一步就是启动它,从而可以很好的使用它,那么如何更好的使用呢?就需要知道DUBBO的各个配置项,以及它可以通过哪些途径进行配置。个人对配置的理解,就好比时对动物的驯服,如何很好的驯服一头猛兽,那就需要知道它各种习性,从而调整,已达到自己期望的结果。这篇不对DUBBO有哪些配置项可以配置,但是通过这篇文章,你应该能够知道DUBBO可以进行哪些配置。本文会通过分析DUBBO加载配置源码的分析,来使得大家对DUBBO的配置一块有更加深入的了解。从而达到“驯服”DUBBO,以使得它成为你们自己的DUBBO。

    DUBBO在配置这一块做的确实很完美,提供很很多参数,以及提供了多种渠道。下面进入正题,看看DUBBO怎么加载配置的。在讲这些之前,先给大家介绍一下在DUBBO源码层面定义了哪些类来存储各个模块的配置项,从而了解DUBBO可以对哪些模块进行配置。

    哪些东西可以配置

    由于大部分项目都会使用Spring,而且DUBBO也提供了通过Spring来进行配置,那么先从这里进行着手。DUBBO加载Spring的集成时在dubbo-config下面的dubbo-config-spring模块下面,其中有一个类DubboNamespaceHandler,它实现了Spring提供的接口NamespaceHandlerSupport。那么Spring怎么发现整个实现类的呢?在该模块的META-INF文件夹下有两个文件: spring.handlers和spring.schemas,这两个文件里面制定了dubbo的namespace的XSD文件的位置以及dubbo的namespace由DubboNamespaceHandler来处理解析。说了这么多废话,只是想说明Spring是怎么解析<dubbo:.../>配置的。

    知道了DUBBO和Spring关于配置一块时怎么整合的之后,那么你应该就不会诧异Spring怎么那么聪明,能够解析dubbo的namespace。接下来看看DubboNamespaceHandler类里面有什么东西。

    <!--lang:java-->
    public class DubboNamespaceHandler extends NamespaceHandlerSupport {
    
        static {
            Version.checkDuplicate(DubboNamespaceHandler.class);
        }
    
        public void init() {
            registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
            registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
            registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
            registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
            registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
            registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
            registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
            registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
            registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
            registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true));
        }
    
    }
    

    可以看到再init方法里面都是调用一个方法registerBeanDefinitionParser,但是参数略微有些不同。registerBeanDefinitionParser方法的第一个参数是dubbo的namespace下面节点名称,第二个参数时该节点由谁来进行解析。例如:registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));是解析<dubbo:application../>配置信息的,依此类推通过Spring可以配置<dubbo:module../>,<dubbo:registry../>等等,就不一一列举了。至于每个标签配置的作用,由于不是本篇的内容,所以这里就不做过多的介绍。

    通过上面应该清楚知道DUBBO可以配置哪些?这个问题应该不会再困扰你了。下面看看DUBBO是怎么加载这些配置项的。

    如何读取我们的配置

    通过Spring的Bean配置读取

    在项目中,会配置Spring的XML(虽然DUBBO也支持注解形式,但是个人不是很推崇,因为这样会将DUBBO整合到你的项目源码里面,而我的建议是不要讲DUBBO和你的项目绑的太紧,我的建议是DUBBO的配置和项目隔离,从而方便管理,加入以后项目不使用DUBBO,而使用其他的分布式RPC框架,对项目的调整会比较小),比如经常会通过下面的配置项引用一个远程的服务:

    <!--lang:xml-->
    <dubbo:reference id="demoService" interface="com.alibaba.dubbo.demo.DemoService" timeout="2000" check="false"/>
    

    通过上面的内容,应该知道dubbo:reference将会由new DubboBeanDefinitionParser(ReferenceBean.class, false)来解析(虽然看上去貌似所有配置都是用DubboBeanDefinitionParser来解析,但是有很大的不同)。那看看类DubboBeanDefinitionParser里面做了什么事情。

    <!--lang:java-->
    public class DubboBeanDefinitionParser implements BeanDefinitionParser {
    
    private static final Logger logger = LoggerFactory.getLogger(DubboBeanDefinitionParser.class);
    
    private final Class<?> beanClass;
    
    private final boolean required;
    
    public DubboBeanDefinitionParser(Class<?> beanClass, boolean required) {
        this.beanClass = beanClass;
        this.required = required;
    }
    
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        return parse(element, parserContext, beanClass, required);
    }
    @SuppressWarnings("unchecked")
    private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {....}
    }
    

    首先看类的定义,DubboBeanDefinitionParser实现了Spring的BeanDefinitionParser接口,该接口时专门用来解析Bean的定义的(一看类名就应该知道),并且实现了public BeanDefinition parse(Element element, ParserContext parserContext)方法(别看整个方法返回了一个BeanDefinition对象,其实Spring并没有利用整个返回的对象,具体你可以看看Spring的源码,所以要把Bean的定义注入到Spring容器中,就需要手动的往Spring中注入,因为Spring没有给我们来做这件事请。),然后调用了静态方法private static BeanDefinition parse(...),那么该类主要就是在静态的方法parse上了。由于该方法内容实在是太长了,不便粘贴出全部内容,我只分析主要的部分。在DubboBeanDefinitionParser构造方法参数上有一个Class<?> beanClass参数,它就是指定讲当前标签配置内容转换成对应类的BeanDefinition并且注入到Spring容器中。

    <!--lang:java-->
    private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {
        RootBeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClass(beanClass);
        beanDefinition.setLazyInit(false);
        String id = element.getAttribute("id");
        if ((id == null || id.length() == 0) && required) {
            //构造一个Bean的ID
        }
        ....
        parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
        ....
         for (Method setter : beanClass.getMethods()) {
            String name = setter.getName();
            if (name.length() > 3 && name.startsWith("set")
                    && Modifier.isPublic(setter.getModifiers())
                    && setter.getParameterTypes().length == 1) {
                Class<?> type = setter.getParameterTypes()[0];
                String property = StringUtils.camelToSplitName(name.substring(3, 4).toLowerCase() + name.substring(4), "-");
                props.add(property);
                Method getter = null;
                try {
                    getter = beanClass.getMethod("get" + name.substring(3), new Class<?>[0]);
                } catch (NoSuchMethodException e) {
                    try {
                        getter = beanClass.getMethod("is" + name.substring(3), new Class<?>[0]);
                    } catch (NoSuchMethodException e2) {
                    }
                }
                if (getter == null 
                        || ! Modifier.isPublic(getter.getModifiers())
                        || ! type.equals(getter.getReturnType())) {
                    continue;
                }
                if ("parameters".equals(property)) {
                    parameters = parseParameters(element.getChildNodes(), beanDefinition);
                } else if ("methods".equals(property)) {
                    parseMethods(id, element.getChildNodes(), beanDefinition, parserContext);
                } else if ("arguments".equals(property)) {
                    parseArguments(id, element.getChildNodes(), beanDefinition, parserContext);
                }
            .....
            beanDefinition.getPropertyValues().addPropertyValue(property, reference);
            ......
    

    上面代码很显然看到是通过反射的形式获取类的get/set方法然,从而判断该参数是否可以通过Spring注入进去,最后添加到beanDefinition中,并且注入到Spring容器中。上面则是从Spring中加载配置的机制。

    通过java运行命令-D以及properties中获取配置

    上面内容看到DUBBO可以对哪些模块进行配置,并且通过哪些类来存储这些配置信息,例如:ReferenceBean,RegistryConfig,ServiceBean等,如果进去看看这些类的定义会发现他们都继承了AbstractConfig抽象类,该抽象类中定义了protected static void appendProperties(AbstractConfig config)方法,参数时一个实现它自己的子类,接下来看看它做了什么:

    <!--lang:java-->
    protected static void appendProperties(AbstractConfig config) {
        if (config == null) {
            return;
        }
        String prefix = "dubbo." + getTagName(config.getClass()) + ".";
        Method[] methods = config.getClass().getMethods();
        for (Method method : methods) {
            try {
                String name = method.getName();
                if (name.length() > 3 && name.startsWith("set") && Modifier.isPublic(method.getModifiers()) 
                        && method.getParameterTypes().length == 1 && isPrimitive(method.getParameterTypes()[0])) {
                    String property = StringUtils.camelToSplitName(name.substring(3, 4).toLowerCase() + name.substring(4), "-");
    
                    String value = null;
                    if (config.getId() != null && config.getId().length() > 0) {
                        String pn = prefix + config.getId() + "." + property;
                        value = System.getProperty(pn);
                        if(! StringUtils.isBlank(value)) {
                            logger.info("Use System Property " + pn + " to config dubbo");
                        }
                    }
                    if (value == null || value.length() == 0) {
                        String pn = prefix + property;
                        value = System.getProperty(pn);
                        if(! StringUtils.isBlank(value)) {
                            logger.info("Use System Property " + pn + " to config dubbo");
                        }
                    }
                    if (value == null || value.length() == 0) {
                        Method getter;
                        try {
                            getter = config.getClass().getMethod("get" + name.substring(3), new Class<?>[0]);
                        } catch (NoSuchMethodException e) {
                            try {
                                getter = config.getClass().getMethod("is" + name.substring(3), new Class<?>[0]);
                            } catch (NoSuchMethodException e2) {
                                getter = null;
                            }
                        }
                        if (getter != null) {
                            if (getter.invoke(config, new Object[0]) == null) {
                                if (config.getId() != null && config.getId().length() > 0) {
                                    value = ConfigUtils.getProperty(prefix + config.getId() + "." + property);
                                }
                                if (value == null || value.length() == 0) {
                                    value = ConfigUtils.getProperty(prefix + property);
                                }
                                if (value == null || value.length() == 0) {
                                    String legacyKey = legacyProperties.get(prefix + property);
                                    if (legacyKey != null && legacyKey.length() > 0) {
                                        value = convertLegacyValue(legacyKey, ConfigUtils.getProperty(legacyKey));
                                    }
                                }
    
                            }
                        }
                    }
                    if (value != null && value.length() > 0) {
                        method.invoke(config, new Object[] {convertPrimitive(method.getParameterTypes()[0], value)});
                    }
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }
    }
    

    上面方法一开始是生产当前配置的前缀String prefix = "dubbo." + getTagName(config.getClass()) + ".",此处可以看到dubbo的所有配置项都是以dubbo.开始的,接下来是通过getTagName方法生成当前配置类的配置名称,进去看看getTagName是怎么为各个配置类生成各自的配置名的。

    <!--lang:java-->
    private static final String[] SUFFIXS = new String[] {"Config", "Bean"};
    private static String getTagName(Class<?> cls) {
        String tag = cls.getSimpleName();
        for (String suffix : SUFFIXS) {
            if (tag.endsWith(suffix)) {
                tag = tag.substring(0, tag.length() - suffix.length());
                break;
            }
        }
        tag = tag.toLowerCase();
        return tag;
    }
    

    分析上面的代码很清楚的知道是怎么生成各自配置类的配置名的,比如:ReferenceBean通过该方法会返回reference。所以关于引用远程Bean的配置都是以dubbo.reference.开头的。生成当前配置类的前缀之后,那么还是按照管理反射出当前类的所有set方法,接下来就是从System.getProperty中取,如果其中没有则会从ConfigUtils.getProperty中取。其中需要注意的是:从System.getProperty中取值并没有判断当前属性是否有值(通过spring注入的),而从ConfigUtils.getProperty中取会判断是否有值,如果没有才会从其中取,这里可以说明DUBBO配置项的优先级java -D优先于Spring配置,Spring配置优先于properties文件的配置,这也符合一般项目的规则。不知道大家注意到没,不管是System.getProperty还是ConfigUtils.getProperty都会取两次,一次是String pn = prefix + config.getId() + "." + property,另一次是String pn = prefix + property,这两种的区别就是多了一个config.getId(),可能会好奇config.getId()是什么内容呢?在介绍Spring加载配置的时候,应该知道config对象其实是Spring容器里面的,那么这里的getId,其实就是我们在配置Spring的Bean时候配置的ID。例如:

    <!--lang:java-->
    <dubbo:reference id="demoService" interface="com.alibaba.dubbo.demo.DemoService" timeout="2000" check="false" />
    

    该配置会产生一个ReferenceBean对象,那么此时的config.getId()就是demoService。所以String pn = prefix + config.getId() + "." + property配置的目的是有没有针对当前某个Bean的配置项。比如:配置dubbo消费端的超时时间,一般通过dubbo.reference.timeout,这其实是指定消费端所有Bean的超时时间。有时候我们需要指定某个Bean超时时间可以通过dubbo.reference.{beanId}.timeout来指定,例如上面的可以通过dubbo.reference.demoService.timeout来配置该Bean的超时时间。

    到此对DUBBO所有配置途径以及其原理进行了分析和介绍,貌似还没说怎么取发现dubbo有哪些配置。这里教大家怎么去发现DUBBO有哪些配置。上面介绍过,DUBBO将配置项设置到各个配置类的实体中都是通过判断是否有get/set方法,到这里大家应该清楚怎么去发现了吧?就是如果想了解dubbo某个模块的配置,直接到对应的配置类中看它有哪些字段,知道它的字段名,以及确定你要配置的范围,是全局还是某个bean,还有你想通过什么途径来配置,按照dubbo提供的规则很好确定对应的字段怎么来进行配置。那么你可能会说,字段时一个单词知道是怎么配置,那么如果字段时多个单词组合的呢?由于java的编码风格一般时驼峰格式第:第一个单词首字母小写后面单词首字母大写,那么这种情况对应dubbo来说怎么获取该配置项呢?看下面:

    <!--lang:java-->
      //name是get/set方法名
     String property = StringUtils.camelToSplitName(name.substring(3, 4).toLowerCase() + name.substring(4), "-");
    

    不难发现对于驼峰,dubbo时通过-字符来分割各个单词。其实到这里基本上可以很好的配置DUBBO了,但是有一个上面的途径如果需要调整参数都需要重启应用,达不到动态调整,于是dubbo为了能够满足在项目不重启的情况下可以动态的调整配置参数。

    通过DUBBO管理应用添加动态配置

    这种方式主要原理就是通过管理器将动态参数发布到注册中心(zookeeper)中,然后各个节点可以获得最新的配置变更,然后进行动态调整。想知道这一块内容,需要取看看类RegistryDirectory的实现,该类它实现了NotifyListener。那么它就可以监听到注册中心的任何变更。再了解RegistryDirectory之前,先看看DUBBO对每个服务在注册中心存储了哪些信息?如果用的时zookeeper,那么你会在每个服务节点目录下面看到一下几个目录consumers,providers,configurators,routers。其中动态配置时放在configurators节点目录下。服务消费端会监听configurators目录变更,如果变更则会调用RegistryDirectoryvoid notify(List<URL> urls)方法。监听configurators目录变更触发的void notify(List<URL> urls)方法时,urls的是类似override://...,表示将覆盖调用该服务的某些配置(dubbo中对所有的调用配置都是通过URL的形式来展示的),讲这些URL上面的参数信息替换到调用服务端的URL上面取,并且重新构造该服务的Invoke对象,从而达到更新参数的目的。

    可以给接口的方法配置参数

    整个场景在实际项目中是存在的,比如一个接口存在多个方法,有时候讲参数配置现在再接口层面还是不够的,需要精确到方法级别,例如对接口调用的超时时间设置。dubbo对与方法级别的配置提供了两种途径。

    Spring Bean的方式配置

    如下进行配置:
    
    <!--lang:xml-->
    <dubbo:reference id="demoService" interface="com.alibaba.dubbo.demo.DemoService" timeout="2000" check="false" >
            <dubbo:method name="sayHello" timeout="1000"/>
    </dubbo:reference>
    

    通过多嵌套一个dubbo:method标签来实现。

    动态配置

    在DUBBO的管理器提供了动态配置的功能,通过添加动态配置,以及指定通知的消费端来指定某个服务的某个方法调整参数。它那里配置的规则时方法名加配置项的名称,例如:key配置成:sayHello.timeout,value=”10000”。那么管理器会在注册中心的对应服务的configurators添加一条override://...?sayHello.timeout=10000节点,指定消费端会监听到这个变更,执行上面内容的流程。

    到此关于DUBBO配置已经介绍完毕,可能有一些地方还时没说明清楚,存在疑虑。如果有疑问欢迎提问或者自己取看看相关的DUBBO源码,那一定会了解更加清楚。

    展开全文
  • dubbo配置timeout

    千次阅读 热门讨论 2017-08-27 21:43:10
    最近公司的项目进入测试阶段,发现很多dubbo服务在调用期间会出现timeout的异常情况。解决方案是在服务端配置timeout属性,具体如下...dubbo配置的覆盖规则是provider——>consumer,也就是说consumer的属性会覆盖provi
  • 在eclipse下 使用阿里dubbo分布式框架时,在配置dubbo配置之后,该配置文件会报错,错误如下: 错误信息如下: 报错原因是因为我们对于配置dubbo.xsd约束文件 下载地址: eclipse配置dubbo.xsd,解决标签不...
  • dubbo配置属性详解

    千次阅读 2017-10-27 21:12:41
    dubbo配置指南 转至元数据结尾   转至元数据起始 Configuration Reference Configuration Relation:   SLA配置在此完成!Service Layer Agreement Service Layer Agreement ApplicationConfi
  • Dubbo配置直连

    千次阅读 2018-01-05 03:38:07
    title: Dubbo配置直连 date: 2017-08-31 16:31:30 tags: dubbo 注册中心 直连 registry categories: dubbo 背景 部分小伙伴由于某些原因不能再公司开发。 那么现在提供dubbo直连的相关配置 步骤 使用在...
  • dubbo 配置文件详解

    千次阅读 2016-12-14 22:07:23
    dubbo 配置文件详解 一、dubbo常用配置 dubbo:service/> 服务配置,用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心。 eg、dubbo:service ref=...
  • Dubbo 配置解析

    千次阅读 2019-11-25 22:11:38
    Dubbo配置是基于Spring自定义标签扩展实现的,例如<dubbo:service>、<dubbo:reference>等。Spring在解析到自定义的namespace标签时,会查找对应的spring.schemas和spring.handlers文件。 先看一下...
  • Springboot关于dubbo配置清单

    千次阅读 2018-11-02 12:49:48
    在服务发布者的springboot主配置文件application.properties中添加dubbo配置 #dubbo服务名 spring.dubbo.application.name=xxx #注册中中心 spring.dubbo.registry.address=zookeeper://127.0.0.1:2181 #dubbo的...
  • springboot+dubbo配置走过的坑

    万次阅读 2017-12-04 19:40:52
    一、增加dubbo配置 接收一个springboot项目,需要加上我们的dubbo服务接口(消费者): 起初在网上找到的配置(如下):   spring: dubbo : application : name : hello-world-app registry : ad...
  • 精通Dubbo——Dubbo配置文件详解

    万次阅读 多人点赞 2017-06-01 22:44:35
    依赖的jar理论上Dubbo可以只依赖JDK,不依赖于任何三方库运行,只需配置使用JDK相关实现策略。缺省依赖(系统默认)通过mvn dependency:tree > dep.log命令(Eclipse或Linux命令行)分析,Dubbo缺省依赖以下三方库:...
  • Davids原理探究:Dubbo配置解析原理

    千次阅读 2020-06-24 22:29:04
    文章目录Dubbo配置解析原理配置解析原理基于XML配置解析原理schema模块说明基于注解配置解析原理@EnableDubboServiceAnnotationBeanPostProcessor的作用ReferenceAnnotationBeanPostProcessor的作用 Dubbo配置解析...
  • dubbo配置项简介及配置加载顺序

    千次阅读 2017-03-27 19:31:02
    dubbo配置项 标签 介绍 - 服务配置,用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心。 - 引用配置,用于引用一个暴露的远程服务,一个引用...
  • dubbo配置timeout超时时间

    千次阅读 2018-12-03 19:57:34
    dubbo配置timeout超时时间 在dubbo的provider和consumer的配置文件中,如果都配置了timeout的超时时间,dubbo默认以consumer中配置的时间为准。 provider.xml的配置: &lt;dubbo:service timeout="4000&...
  • dubbo配置文件

    2018-11-01 15:05:59
    一、配置文件组成 dubbo:application 应用信息 dubbo:registry 注册中心 dubbo:monitor 监控中心 dubbo:provider 服务提供者 dubbo:service 暴露服务 dubbo:protocol 协议信息 dubbo:consumer 服务消费者 ...
  • dubbo 知识总结 dubbo配置参考

    万次阅读 多人点赞 2016-11-03 21:11:32
    dubbo官方文档项目的规模越来越大,总得解耦,不能在一个项目里,这时候,公司采用了dubbo作为分布式应用,将多项业务拆分,并做了库存服务统一、价格服务统一等等一些特殊需要统一性的服务。作为dubbo我也接触了快...
  • dubbo配置中心-Apollo部署及使用

    千次阅读 2019-11-28 13:35:05
    dubbo配置中心-Apollo部署及使用 文章目录dubbo配置中心-Apollo部署及使用一、简介二、安装部署1.硬件准备2.组成介绍3.配置并打包a.数据库初始化b.调整配置并打包4.部署三、使用配置中心1.maven配置2.创建app....
  • spring的dubbo配置文件报错

    千次阅读 2017-05-04 13:45:32
    今天导入一个新的maven项目,spring的dubbo配置文件报错(有dubbo标签的都出现了),配置文件如下: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xmlns:context=...
  • 之前我们简单介绍了dubbo配置服务提供者、消费者以及管理平台监控平台,接下来我们再说一下dubbo的配置。 1.配置策略 1.1 属性配置 dubbo可以在JVM 启动参数、dubboXML、dubbo.properties 三个地方配置,这里我们以...
  • Dubbo配置详解

    千次阅读 2019-03-20 22:28:25
    基本配置 服务端 <!-- 提供方应用信息,用于计算依赖关系 --> <dubbo:application name="storeServer"/> <!-- 使用zookeeper注册中心暴露服务地址 --> <dubbo:registry address=...
  • 你真的了解dubbo配置优先级吗?

    千次阅读 2019-08-01 11:21:24
    dubbo配置的优先级: (1)方法 > 接口:方法级别的配置总是优于接口级别的配置,很显然,提供者端的方法配置优先级要高于消费者端的接口配置 (2)消费者 > 提供者 (3)全局配置优先级最低 ...
  • Springboot改造之配置--Dubbo配置

    千次阅读 2018-04-12 18:01:47
    接上一篇,api模块很简单,就是对外提供接口,所以就不做介绍了,下面讲一下Sprintboot 中对dubbo配置dubbo配置在 core 模块,首先来看一下在项目中的位置: 左侧选中的三行就是dubbo主要的配置,...
  • dubbo配置文件报错

    2014-09-05 16:56:34
    dubbo我在网上下载了一个例子导入Eclipse里面报错说 Multiple annotations found at this line: - cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element '...
  • 配置参考手册 <dubbo:service/> <dubbo:reference/> <dubbo:protocol/> <dubbo:registry/> <dubbo:monitor/> <dubbo:application/> <dubbo:module/> <...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 89,115
精华内容 35,646
关键字:

dubbo配置