2. 架构设计

Dubbo 定义了以下核心角色:

  1. Provider - 服务提供方,负责暴露服务并注册到注册中心
  2. Container - 服务容器,负责启动、加载和运行服务
  3. Consumer - 服务消费方,通过注册中心订阅所需服务
  4. Registry - 注册中心,用于服务注册与发现
  5. Monitor - 监控中心,记录服务调用统计信息(如指定时间内的调用频率)

Dubbo 架构图 (来源: http://dubbo.io/images/dubbo-architecture.png)

✅ Provider、Consumer 和 Registry 之间保持长连接,当服务提供者宕机时,注册中心能立即感知并通知消费者 ⚠️ Registry 和 Monitor 是可选组件,消费者可直接连接提供者,但会影响系统稳定性

3. Maven 依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.5.7</version>
</dependency>

最新版本可查阅 Maven 中央仓库

4. 快速上手

4.1. 多播注册中心 - 服务提供者

public interface GreetingsService {
    String sayHi(String name);
}

public class GreetingsServiceImpl implements GreetingsService {
    @Override
    public String sayHi(String name) {
        return "hi, " + name;
    }
}

💡 消费者和提供者必须共享接口定义,这是实现远程调用的基础

4.2. 多播注册中心 - 服务注册

<dubbo:application name="demo-provider" version="1.0"/>
<dubbo:registry address="multicast://224.1.1.1:9090"/>
<dubbo:protocol name="dubbo" port="20880"/>
<bean id="greetingsService" class="com.baeldung.dubbo.remote.GreetingsServiceImpl"/>
<dubbo:service interface="com.baeldung.dubbo.remote.GreetingsService"
  ref="greetingsService"/>

通过此配置,服务将暴露在 dubbo://127.0.0.1:20880 并注册到多播地址

  • <dubbo:application> 定义应用元数据
  • <dubbo:protocol> 指定通信协议(默认基于 NIO)
  • <dubbo:service> 声明要发布的服务接口

4.3. 多播注册中心 - 服务消费者

<dubbo:application name="demo-consumer" version="1.0"/>
<dubbo:registry address="multicast://224.1.1.1:9090"/>
<dubbo:reference interface="com.baeldung.dubbo.remote.GreetingsService"
  id="greetingsService"/>

验证代码:

public class MulticastRegistryTest {
    @Before
    public void initRemote() {
        ClassPathXmlApplicationContext remoteContext
          = new ClassPathXmlApplicationContext("multicast/provider-app.xml");
        remoteContext.start();
    }

    @Test
    public void givenProvider_whenConsumerSaysHi_thenGotResponse(){
        ClassPathXmlApplicationContext localContext 
          = new ClassPathXmlApplicationContext("multicast/consumer-app.xml");
        localContext.start();
        GreetingsService greetingsService
          = (GreetingsService) localContext.getBean("greetingsService");
        String hiMessage = greetingsService.sayHi("baeldung");

        assertNotNull(hiMessage);
        assertEquals("hi, baeldung", hiMessage);
    }
}

🔍 消费者通过代理透明调用远程服务,无需感知底层实现 ❌ 直连方式(不推荐): url="dubbo://127.0.0.1:20880"

4.4. 简单注册中心

<dubbo:application name="simple-registry" />
<dubbo:protocol port="9090" />
<dubbo:service interface="com.alibaba.dubbo.registry.RegistryService"
  ref="registryService" registry="N/A" ondisconnect="disconnect">
    <dubbo:method name="subscribe">
        <dubbo:argument index="1" callback="true" />
    </dubbo:method>
    <dubbo:method name="unsubscribe">
        <dubbo:argument index="1" callback="true" />
    </dubbo:method>
</dubbo:service>

<bean class="com.alibaba.dubbo.registry.simple.SimpleRegistryService"
  id="registryService" />

⚠️ 需从 GitHub 复制源码 ✅ 仅适用于测试环境,生产环境请勿使用

4.5. Java 配置方式

服务提供者配置:

ApplicationConfig application = new ApplicationConfig();
application.setName("demo-provider");
application.setVersion("1.0");

RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("multicast://224.1.1.1:9090");

ServiceConfig<GreetingsService> service = new ServiceConfig<>();
service.setApplication(application);
service.setRegistry(registryConfig);
service.setInterface(GreetingsService.class);
service.setRef(new GreetingsServiceImpl());

service.export();

服务消费者配置:

ApplicationConfig application = new ApplicationConfig();
application.setName("demo-consumer");
application.setVersion("1.0");

RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("multicast://224.1.1.1:9090");

ReferenceConfig<GreetingsService> reference = new ReferenceConfig<>();
reference.setApplication(application);
reference.setRegistry(registryConfig);
reference.setInterface(GreetingsService.class);

GreetingsService greetingsService = reference.get();
String hiMessage = greetingsService.sayHi("baeldung");

💡 复杂场景建议优先使用 XML 配置,功能更完整

5. 协议支持

Dubbo 支持多种协议:

  • dubbo(默认)
  • RMI
  • Hessian
  • HTTP
  • Web Service
  • Thrift
  • Memcached
  • Redis

Dubbo 协议特点:

  • 保持长连接(NIO 非阻塞)
  • 小数据包(<100K)传输性能优异
    <dubbo:protocol name="dubbo" port="20880"
    connections="2" accepts="1000" />
    

多协议暴露示例:

<dubbo:protocol name="dubbo" port="20880" />
<dubbo:protocol name="rmi" port="1099" />

<dubbo:service interface="com.baeldung.dubbo.remote.GreetingsService"
  version="1.0.0" ref="greetingsService" protocol="dubbo" />
<dubbo:service interface="com.bealdung.dubbo.remote.AnotherService"
  version="1.0.0" ref="anotherService" protocol="rmi" />

6. 结果缓存

<dubbo:reference interface="com.baeldung.dubbo.remote.GreetingsService"
  id="greetingsService" cache="lru" />

✅ 支持 LRU、线程本地缓存和 JCache

缓存验证代码:

public class GreetingsServiceSpecialImpl implements GreetingsService {
    @Override
    public String sayHi(String name) {
        try {
            SECONDS.sleep(5); // 模拟耗时操作
        } catch (Exception ignored) { }
        return "hi, " + name;
    }
}

@Test
public void givenProvider_whenConsumerSaysHi_thenGotResponse() {
    // ... 初始化上下文
    GreetingsService greetingsService = (GreetingsService) localContext.getBean("greetingsService");

    long before = System.currentTimeMillis();
    String hiMessage = greetingsService.sayHi("baeldung");
    long timeElapsed = System.currentTimeMillis() - before;
    assertTrue(timeElapsed > 5000); // 首次调用 >5秒

    before = System.currentTimeMillis();
    hiMessage = greetingsService.sayHi("baeldung");
    timeElapsed = System.currentTimeMillis() - before;
    assertTrue(timeElapsed < 1000); // 缓存命中 <1秒
}

7. 集群支持

7.1. 负载均衡

注册中心配置:

<dubbo:registry address="zookeeper://127.0.0.1:2181"/>

需添加依赖:

<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.11</version>
</dependency>
<dependency>
    <groupId>com.101tec</groupId>
    <artifactId>zkclient</artifactId>
    <version>0.10</version>
</dependency>

负载均衡策略:

  1. random(随机)
  2. roundrobin(轮询)
  3. leastactive(最少活跃)
  4. consistenthash(一致性哈希)

消费者配置:

<dubbo:reference interface="com.baeldung.dubbo.remote.GreetingsService"
  id="greetingsService" loadbalance="roundrobin" />

动态负载均衡验证:

@Test
public void givenProviderCluster_whenConsumerSaysHi_thenResponseBalanced() {
    // ... 初始化上下文
    GreetingsService greetingsService = (GreetingsService) localContext.getBean("greetingsService");
    List<Long> elapseList = new ArrayList<>(6);
    
    for (int i = 0; i < 6; i++) {
        long current = System.currentTimeMillis();
        greetingsService.sayHi("baeldung");
        elapseList.add(System.currentTimeMillis() - current);
    }

    OptionalDouble avgElapse = elapseList.stream().mapToLong(e -> e).average();
    assertTrue(avgElapse.getAsDouble() > 2500.0); // 平均耗时 >2.5秒
}

💡 集群包含快速响应提供者(0秒)和慢速提供者(5秒),轮询策略下平均耗时应为 (0+5)/2=2.5秒

7.2. 容错策略

支持策略:

  • failover(失败自动切换)
  • failsafe(失败安全)
  • failfast(快速失败)
  • failback(失败重试)
  • forking(并行调用)

容错配置示例:

<dubbo:service interface="com.baeldung.dubbo.remote.GreetingsService"
  ref="greetingsService" cluster="failover"/>

失败重试验证:

public class GreetingsFailoverServiceImpl implements GreetingsService {
    @Override
    public String sayHi(String name) {
        return "hi, failover " + name;
    }
}

// 消费者配置:retries="2" timeout="2000"
@Test
public void whenConsumerSaysHi_thenGotFailoverResponse() {
    // ... 初始化上下文
    GreetingsService greetingsService = (GreetingsService) localContext.getBean("greetingsService");
    String hiMessage = greetingsService.sayHi("baeldung");
    
    assertEquals("hi, failover baeldung", hiMessage); // 超时后切换到备用服务
}

8. 总结

Dubbo 作为阿里巴巴开源的 RPC 框架,其核心优势在于:

  • ✅ 简洁易用的服务治理能力
  • ✅ 支持平滑重构单体应用到分布式架构
  • ✅ 丰富的扩展特性(多协议、集群、缓存等)

💡 本文仅介绍基础功能,更多高级特性如参数校验、回调通知、泛化调用等待探索。完整示例代码请参考 GitHub 仓库


原始标题:Introduction to Dubbo | Baeldung