(7)Dubbo的四种配置方式

x33g5p2x  于2021-12-21 转载在 其他  
字(13.0k)|赞(0)|评价(0)|浏览(555)

本节介绍

Dubbo共有四种配置方式:xml配置、dubbo.properties属性配置、API配置、注解配置。本节将会对这四种方式分别做下介绍,同时也会对主要的配置方式给出范例。

一:xml配置

所有配置项分为三大类,参见下表中的"作用" 一列。

  • 服务发现:表示该配置项用于服务的注册与发现,目的是让消费方找到提供方。
  • 服务治理:表示该配置项用于治理服务间的关系,或为开发测试提供便利条件。
  • 性能调优:表示该配置项用于调优性能,不同的选项对性能会产生影响。
  • 所有配置最终都将转换为 URL 表示,并由服务提供方生成,经注册中心传递给消费方,各属性对应 URL 的参数,参见配置项一览表中的 "对应URL参数" 列。
  1. XML Schema: http://dubbo.apache.org/schema/dubbo/dubbo.xsd↩︎
  2. 注意:只有 group,interface,version 是服务的匹配条件,三者决定是不是同一个服务,其它配置项均为调优和治理参数。
  3. URL 格式:protocol://username:password@host:port/path?key=value&key=value

xml的配置案例这里不再演示,《二、Dubbo入门使用案例》中就是使用的xml配置方式。

配置之间的关系

标签用途解释
<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/>参数配置用于指定方法参数配置

配置覆盖关系

以 timeout 为例,显示了配置的查找顺序,其它 retries, loadbalance, actives 等类似:

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

其中,服务提供方配置,通过 URL 经由注册中心传递给消费方。

建议由服务提供方设置超时,因为一个方法需要执行多长时间,服务提供方更清楚,如果一个消费方同时引用多个服务,就不需要关心每个服务的超时设置。

理论上 ReferenceConfig 的非服务标识配置,在 ConsumerConfig,ServiceConfig, ProviderConfig 均可以缺省配置。

  1. 2.1.0 开始支持,注意声明:xmlns:p="http://www.springframework.org/schema/p"
  2. 引用缺省是延迟初始化的,只有引用被注入到其它 Bean,或被 getBean() 获取,才会初始化。如果需要饥饿加载,即没有人引用也立即生成动态代理,可以配置:<dubbo:reference ... init="true" />

二:dubbo.properties属性配置

如果公共配置很简单,没有多注册中心,多协议等情况,或者想多个 Spring 容器想共享配置,可以使用 dubbo.properties 作为缺省配置。一般情况下 properties 都是用来配置一些公共的信息,比如可能一个应用需要调用多个注册中心的服务,这时候它们的 application.name、dubbo.protocol.name等都是相同的,那么你可以用 properties 来配置这些公共信息。

Dubbo 将自动加载 classpath 根目录下的 dubbo.properties,可以通过JVM启动参数 -Ddubbo.properties.file=xxx.properties 改变缺省配置位置。

映射规则

将 XML 配置的标签名,加属性名,用点分隔,多个属性拆成多行

  • 比如:dubbo.application.name=foo等价于<dubbo:application name="foo" />
  • 比如:dubbo.registry.address=10.20.153.10:9090等价于<dubbo:registry address="10.20.153.10:9090" />

如果 XML 有多行同名标签配置,可用 id 号区分,如果没有 id 号将对所有同名标签生效

  • 比如:dubbo.protocol.rmi.port=1234等价于<dubbo:protocol id="rmi" name="rmi" port="1099" />
  • 比如:dubbo.registry.china.address=10.20.153.10:9090等价于<dubbo:registry id="china" address="10.20.153.10:9090" />

下面是 dubbo.properties 的一个典型配置:

dubbo.application.name=foo
dubbo.application.owner=bar
dubbo.registry.address=10.20.153.10:9090

覆盖策略

JVM 启动 -D 参数优先,这样可以使用户在部署和启动时进行参数重写,比如在启动时需改变协议的端口。

XML 次之,如果在 XML 中有配置,则 dubbo.properties 中的相应配置项无效。

Properties 最后,相当于缺省值,只有 XML 没有配置时,dubbo.properties 的相应配置项才会生效,通常用于共享公共配置,比如应用名。

  1. 如果 classpath 根目录下存在多个 dubbo.properties,比如多个 jar 包中有 dubbo.properties,Dubbo 会任意加载,并打印 Error 日志,后续可能改为抛异常。 ↩︎
  2. 协议的 id 没配时,缺省使用协议名作为 id ↩︎

服务容器

Dubbo服务容器是一个 standalone 的启动程序,因为后台服务不需要 Tomcat 或 JBoss 等 Web 容器的功能,如果硬要用 Web 容器去加载服务提供方,增加复杂性,也浪费资源。

服务容器只是一个简单的 Main 方法,并加载一个简单的 Spring 容器,用于暴露服务。

服务容器的加载内容可以扩展,内置了 spring, jetty, log4j 等加载,可通过容器扩展点进行扩展。配置配在 java 命令的 -D 参数或者 dubbo.properties 中。

Spring Container

  • 自动加载 META-INF/spring 目录下的所有 Spring 配置。
  • 配置 spring 配置加载位置:
dubbo.spring.config=classpath*:META-INF/spring/*.xml

 dubbo.properties使用案例

将《二、Dubbo入门使用案例》中的simple-provider项目进行改造。改造之后结构如下:

dubbo.properties配置文件如下:修改了Dubbo的默认配置文件位置(META-INF/spring 目录下的所有 Spring 配置)

dubbo.application.name=simple-provider
dubbo.registry.address=zookeeper://192.168.74.4:2181?backup=192.168.74.5:2181,192.168.74.6:2181
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
dubbo.spring.config=classpath:simple-provider.xml

xml配置修改成如下内容:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
	
	<!-- 具体的实现bean -->
	<bean id="simpleService" class="com.wkp.service.simple.impl.SimpleServiceImpl" />

	<!-- 声明需要暴露的服务接口  写操作可以设置retries=0 避免重复调用SOA服务 -->
	<dubbo:service retries="0" interface="com.wkp.service.simple.SimpleService" ref="simpleService" />
</beans>

启动类修改为

package com.wkp.service.simple.provider;

import com.alibaba.dubbo.container.Main;

public class Provider {

	public static void main(String[] args) throws Exception {
//		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
//				new String[] { "simple-provider.xml" });
//		context.start(); 
//		System.in.read(); // 为保证服务一直开着,利用输入流的阻塞来模拟
		Main.main(args);
	}
}

运行上面的启动类,发现服务正常启动,说明改造成功。

三:API 配置

API 属性与配置项一对一,比如:ApplicationConfig.setName("xxx") 对应 <dubbo:application name="xxx" />,API使用范围说明:API 仅用于 OpenAPI, ESB, Test, Mock 等系统集成,官方不推荐此种方式,所以这里也不做重点介绍了。

服务提供者

import com.alibaba.dubbo.rpc.config.ApplicationConfig;
import com.alibaba.dubbo.rpc.config.RegistryConfig;
import com.alibaba.dubbo.rpc.config.ProviderConfig;
import com.alibaba.dubbo.rpc.config.ServiceConfig;
import com.xxx.XxxService;
import com.xxx.XxxServiceImpl;
 
// 服务实现
XxxService xxxService = new XxxServiceImpl();
 
// 当前应用配置
ApplicationConfig application = new ApplicationConfig();
application.setName("xxx");
 
// 连接注册中心配置
RegistryConfig registry = new RegistryConfig();
registry.setAddress("10.20.130.230:9090");
registry.setUsername("aaa");
registry.setPassword("bbb");
 
// 服务提供者协议配置
ProtocolConfig protocol = new ProtocolConfig();
protocol.setName("dubbo");
protocol.setPort(12345);
protocol.setThreads(200);
 
// 注意:ServiceConfig为重对象,内部封装了与注册中心的连接,以及开启服务端口
 
// 服务提供者暴露服务配置
ServiceConfig<XxxService> service = new ServiceConfig<XxxService>(); // 此实例很重,封装了与注册中心的连接,请自行缓存,否则可能造成内存和连接泄漏
service.setApplication(application);
service.setRegistry(registry); // 多个注册中心可以用setRegistries()
service.setProtocol(protocol); // 多个协议可以用setProtocols()
service.setInterface(XxxService.class);
service.setRef(xxxService);
service.setVersion("1.0.0");
 
// 暴露及注册服务
service.export();

服务消费者

import com.alibaba.dubbo.rpc.config.ApplicationConfig;
import com.alibaba.dubbo.rpc.config.RegistryConfig;
import com.alibaba.dubbo.rpc.config.ConsumerConfig;
import com.alibaba.dubbo.rpc.config.ReferenceConfig;
import com.xxx.XxxService;
 
// 当前应用配置
ApplicationConfig application = new ApplicationConfig();
application.setName("yyy");
 
// 连接注册中心配置
RegistryConfig registry = new RegistryConfig();
registry.setAddress("10.20.130.230:9090");
registry.setUsername("aaa");
registry.setPassword("bbb");
 
// 注意:ReferenceConfig为重对象,内部封装了与注册中心的连接,以及与服务提供方的连接
 
// 引用远程服务
ReferenceConfig<XxxService> reference = new ReferenceConfig<XxxService>(); // 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏
reference.setApplication(application);
reference.setRegistry(registry); // 多个注册中心可以用setRegistries()
reference.setInterface(XxxService.class);
reference.setVersion("1.0.0");
 
// 和本地bean一样使用xxxService
XxxService xxxService = reference.get(); // 注意:此代理对象内部封装了所有通讯细节,对象较重,请缓存复用

 四:注解配置

@DubboComponentScan 作为 Dubbo2.5.7中 新增的 Annotation,也是XML 元素 <dubbo:annotation package="com.alibaba.dubbo.test.service" />的替代方案(注意:Dubbo2.5.7及以上才支持该注解)。其主要功能在于处理 Dubbo @Service类暴露 Dubbo 服务外,还有帮助 Spring Bean中 @Reference字段或者方法注入 Dubbo 服务代理。其源码如下

/**
 * Dubbo Component Scan {@link Annotation},scans the classpath for annotated components that will be auto-registered as
 * Spring beans. Dubbo-provided {@link Service} and {@link Reference}.
 *
 * @see Service
 * @see Reference
 * @since 2.5.7
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {

    /**
     * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
     * declarations e.g.: {@code @DubboComponentScan("org.my.pkg")} instead of
     * {@code @DubboComponentScan(basePackages="org.my.pkg")}.
     *
     * @return the base packages to scan
     */
    String[] value() default {};

    /**
     * Base packages to scan for annotated @Service classes. {@link #value()} is an
     * alias for (and mutually exclusive with) this attribute.
     * <p>
     * Use {@link #basePackageClasses()} for a type-safe alternative to String-based
     * package names.
     *
     * @return the base packages to scan
     */
    String[] basePackages() default {};

    /**
     * Type-safe alternative to {@link #basePackages()} for specifying the packages to
     * scan for annotated @Service classes. The package of each class specified will be
     * scanned.
     *
     * @return classes from the base packages to scan
     */
    Class<?>[] basePackageClasses() default {};

}

注意: @DubboComponentScan如果没有指定basePackages扫描,这种情况会将当前类当做 basePackageClasses,即扫描当前类所属的 package 以及子 package。

说明:在Dubbo2.5.8及之后出现了新的注解@EnableDubboConfig和@EnableDubbo(是@EnableDubboConfig和@DubboComponentScan的组合),可以用外部化配置(External Configuration)方式进行Dubbo的配置,比@DubboComponentScan注解更加的便捷好用,具体使用方式请参考https://segmentfault.com/a/1190000012661402      http://dubbo.apache.org/zh-cn/blog/dubbo-annotation.html

服务提供方

Service注解暴露服务

import com.alibaba.dubbo.config.annotation.Service;
 
@Service(timeout = 5000)
public class AnnotateServiceImpl implements AnnotateService { 
    // ...
}

javaconfig形式配置公共模块,并制定Dubbo扫描路径

@Configuration
@DubboComponentScan(basePackages = "com.alibaba.dubbo.test.service.impl")
public class DubboConfiguration {

    @Bean
    public ApplicationConfig applicationConfig() {
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("provider-test");
        return applicationConfig;
    }

    @Bean
    public RegistryConfig registryConfig() {
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setAddress("zookeeper://127.0.0.1:2181");
        registryConfig.setClient("curator");
        return registryConfig;
    }
}

服务提供者启动类

@SpringBootApplication
public class ProviderTestApp {
    public static void main(String[] args) throws IOException {
	SpringApplication.run(ProviderTestApp.class, args);
    }
}

** 注意:其实不用springboot的话,也是可以用Dubbo的注解方式的,其启动类就变成了下面这样**

public class ProviderTestApp {

	public static void main(String[] args) throws IOException {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
		context.register(DubboConfiguration.class);
		context.refresh();
		System.in.read();
	}
}

服务消费方

Reference注解引用服务

public class AnnotationConsumeService {

    @com.alibaba.dubbo.config.annotation.Reference
    public AnnotateService annotateService;
    
    // ...
}

javaconfig形式配置公共模块,并制定Dubbo扫描路径

@Configuration
@DubboComponentScan(basePackages = "com.alibaba.dubbo.test.service")
public class DubboConfiguration {

    @Bean
    public ApplicationConfig applicationConfig() {
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("consumer-test");
        return applicationConfig;
    }

    @Bean
    public ConsumerConfig consumerConfig() {
        ConsumerConfig consumerConfig = new ConsumerConfig();
        consumerConfig.setTimeout(3000);
        return consumerConfig;
    }

    @Bean
    public RegistryConfig registryConfig() {
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setAddress("zookeeper://127.0.0.1:2181");
        registryConfig.setClient("curator");
        return registryConfig;
    }
}

消费者启动类

@SpringBootApplication
public class ConsumerTestApp {
     public static void main(String[] args) throws IOException {
	SpringApplication.run(ConsumerTestApp.class, args);
    }
}

注意:服务消费者如果不用springboot的话,一定要将上面引入了@Reference注解的AnnotationConsumerService类变为Spring的bean,方式有两种:第一种是是使用@Bean注解;第二种是在AnnotationConsumerService上面添加@Service(这里是spring的注解),然后再在DubboConfiguration类上添加@ComponentScan来扫描Spring的@Service注解,如果不添加@ComponentScan,则@Service注解无效提示没有这个bean。

下面是第一种方式

@Bean
    public AnnotationConsumerService annotationConsumerService() {
    	return new AnnotationConsumerService();
    }

** 下面是第二种方式:**

import org.springframework.stereotype.Service;
@Service
public class AnnotationConsumeService {

    @com.alibaba.dubbo.config.annotation.Reference
    public AnnotateService annotateService;
    
    // ...
}
@Configuration
@DubboComponentScan(basePackages = "com.alibaba.dubbo.test.service")
@DubboComponent(basePackages = "com.alibaba.dubbo.test.service")
public class DubboConfiguration {

    @Bean
    public ApplicationConfig applicationConfig() {
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("consumer-test");
        return applicationConfig;
    }

    @Bean
    public ConsumerConfig consumerConfig() {
        ConsumerConfig consumerConfig = new ConsumerConfig();
        consumerConfig.setTimeout(3000);
        return consumerConfig;
    }

    @Bean
    public RegistryConfig registryConfig() {
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setAddress("zookeeper://127.0.0.1:2181");
        registryConfig.setClient("curator");
        return registryConfig;
    }
}

消费者不使用SpringBoot的话,可以采用如下方式启动调用

public class ConsumerTestApp {
	
	public static void main(String[] args) throws IOException {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
		context.register(DubboConfiguration.class);
		//启动消费者
		context.refresh();
		AnnotationConsumerService service = context.getBean(AnnotationConsumerService.class);
		//方法调用
//		service.m1();
		System.in.read();
	}
}

注意

如果你曾使用旧版annotation配置,请删除所有相关配置,从2.5.8已删除所有如下旧版配置项。

<dubbo:annotation package="com.alibaba.dubbo.test.service" />

关于Dubbo的四种配置方式就先介绍到这里,关于Dubbo注解这块这里写的比较简单,下一节将会详细的给大家介绍下Dubbo的注解使用以及跟SpringBoot整合的几种方式。

相关文章