一、简介

1、简介

Apache Dubbo是一款高性能、开源的RPC(远程过程调用)服务开发框架,主要用于解决微服务架构中的服务治理与通信问题。

2、核心概念

  • Provider

服务提供方

  • Consumer

服务消费方

  • Registry

服务注册与发现中心,如 Zookeeper、Nacos等。

  • Container

服务运行容器,负责启动、加载、运行 Provider。

  • Monitor

监控中心:统计服务调用次数和调用时间。

3、工作流程

  • 服务提供者(Provider)在启动时,向注册中心(Registry​)注册自己提供的服务。

  • 服务消费者(Consumer​)在启动时,向注册中心(Registry​)订阅自己所需的服务。

  • 注册中心给消费者返回服务提供者地址列表,后续如有变更,注册中心会基于长连接推送变更数据。

  • 服务消费者从提供者地址列表中,基于负载均衡算法选择一台提供者进行调用。

  • 服务消费者和提供者会将调用次数和时间等统计数据异步发送到监控中心(Monitor)。

4、核心对象

  • 服务端

    Dubbo服务端的核心对象有四个:

    • RegistryConfig

      配置注册相关信息

    • ProtocolConfig

      配置提供服务的协议信息

    • ApplicationConfig

      配置当前应用信息

    • ServiceConfig

      配置暴露的服务信息

  • 客户端

    Dubbo服务端的核心对象有两个:

    • ApplicationConfig

      配置当前应用信息

    • ReferenceConfig

      配置引用的服务信息

二、样例

API工程:

  • 模型
package dubbo.model;

import java.io.Serializable;

public class User implements Serializable{

	private static final long serialVersionUID = -4500356404069677105L;

	private Long id;
	private String name;
	private String sex;
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	
	@Override
	public String toString() {
		return String.format("%s:%s %s", id, name, sex);
	}
}
  • 接口
package dubbo.service;

import dubbo.model.User;

public interface UserService {

	User getUser(long id);
	
	default void sayHi(String name) {};
}

1、使用直连方式

  • 服务提供者

依赖:

<dependency>
	<groupId>org.apache.dubbo</groupId>
	<artifactId>dubbo</artifactId>
	<version>2.7.4.1</version>
</dependency>

<dependency>
	<groupId>ch.qos.logback</groupId>
	<artifactId>logback-classic</artifactId>
	<version>1.2.13</version>
</dependency>

服务实现类:

package demo.impl;

import dubbo.model.User;
import dubbo.service.UserService;

public class UserServiceImpl implements UserService{

	@Override
	public User getUser(long id) {
		User user = new User();
		user.setId(id);
		user.setName("ZhangSan");
		user.setSex("male");
		return user;
	}

}

主程序:

package demo;

import java.io.IOException;

import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import demo.impl.UserServiceImpl;
import dubbo.service.UserService;

public class DubboProvider {

	public static void main(String[] args) {
		Logger log = LoggerFactory.getLogger(DubboProvider.class);

		//服务的连接方式
		RegistryConfig registryConfig = new RegistryConfig(RegistryConfig.NO_AVAILABLE);

		//服务协议
		ProtocolConfig protocolConfig = new ProtocolConfig();
		protocolConfig.setName("dubbo");
		protocolConfig.setPort(20990);

		//应用信息
		ApplicationConfig applicationConfig = new ApplicationConfig("sample-provider");

		//服务信息
		ServiceConfig<UserService> serviceConfig = new ServiceConfig<>();
		serviceConfig.setInterface(UserService.class);
		serviceConfig.setRef(new UserServiceImpl());
		serviceConfig.setRegistry(registryConfig);
		serviceConfig.setProtocol(protocolConfig);
		serviceConfig.setApplication(applicationConfig);
		serviceConfig.export();

		log.info("service is ready");
		try {
			System.in.read();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}
}
  • 服务消费者

依赖同服务提供者。

主程序:

package demo;

import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;

import dubbo.model.User;
import dubbo.service.UserService;

public class DubboConsumer {

	public static void main(String[] args) {
		Logger log = LoggerFactory.getLogger(DubboConsumer.class);

		//应用信息
		ApplicationConfig applicationConfig = new ApplicationConfig("simple-consumer");

		//引用的服务信息
		ReferenceConfig<UserService> referenceConfig = new ReferenceConfig<UserService>();
		referenceConfig.setApplication(applicationConfig);
		referenceConfig.setInterface(UserService.class);
		referenceConfig.setUrl("dubbo://localhost:20990");

		//获取接口
		UserService service = referenceConfig.get();
		//调用服务
		User user = service.getUser(1);
		log.info(user.toString());
	}
}

2、使用Zookeeper

  • 服务提供者

依赖:

<dependency>
	<groupId>org.apache.dubbo</groupId>
	<artifactId>dubbo</artifactId>
	<version>2.7.4.1</version>
</dependency>

<dependency>
	<groupId>ch.qos.logback</groupId>
	<artifactId>logback-classic</artifactId>
	<version>1.2.13</version>
</dependency>

<dependency>
	<groupId>org.apache.curator</groupId>
	<artifactId>curator-recipes</artifactId>
	<version>5.5.0</version>
</dependency>
<dependency>
	<groupId>org.apache.curator</groupId>
	<artifactId>curator-framework</artifactId>
	<version>5.5.0</version>
</dependency>

主程序:

package demo;

import java.io.IOException;

import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import demo.impl.UserServiceImpl;
import dubbo.service.UserService;

public class DubboZookeeperProvider {

	public static void main(String[] args) {
		Logger log = LoggerFactory.getLogger(DubboZookeeperProvider.class);
		
		RegistryConfig registryConfig = new RegistryConfig("zookeeper://localhost:2181");

		ProtocolConfig protocolConfig = new ProtocolConfig();
		protocolConfig.setName("dubbo");
		protocolConfig.setPort(20990);

		ApplicationConfig applicationConfig = new ApplicationConfig("sample-provider-zk");

		ServiceConfig<UserService> serviceConfig = new ServiceConfig<UserService>();
		serviceConfig.setInterface(UserService.class);
		serviceConfig.setRef(new UserServiceImpl());
		serviceConfig.setRegistry(registryConfig);
		serviceConfig.setProtocol(protocolConfig);
		serviceConfig.setApplication(applicationConfig);
		serviceConfig.export();
		
		log.info("service is ready");
		
		try {
			System.in.read();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

  • 服务消费者

依赖同服务提供者。

主程序:

package demo;

import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import dubbo.model.User;
import dubbo.service.UserService;

public class DubboZookeeperConsumer {

	public static void main(String[] args) {
		Logger log = LoggerFactory.getLogger(DubboZookeeperConsumer.class);
	
		RegistryConfig registryConfig = new RegistryConfig("zookeeper://localhost:2181");

		ApplicationConfig applicationConfig = new ApplicationConfig("simple-consumer-zk");

		ReferenceConfig<UserService> referenceConfig = new ReferenceConfig<UserService>();
		referenceConfig.setInterface(UserService.class);
		referenceConfig.setApplication(applicationConfig);
		referenceConfig.setRegistry(registryConfig);

		UserService service = referenceConfig.get();
		User user = service.getUser(1);
		log.info(user.toString());
	}
}

3、使用Spring和Zookeeper

pom.xml中的依赖和上一个样例中的相同。

  • 服务提供者

Spring配置文件provider.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://dubbo.apache.org/schema/dubbo
                           http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

	<dubbo:application name="sample-provider-sp"/>
	<dubbo:registry address="zookeeper://localhost:2181"/>
	<dubbo:protocol name="dubbo" port="20990"/>
	<dubbo:service interface="dubbo.service.UserService" ref="userService"/>
	
	<bean id="userService" class="demo.impl.UserServiceImpl"></bean>
</beans>

主程序:

package demo;

import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DubboZKSpringProvider {

	public static void main(String[] args) {
		Logger log = LoggerFactory.getLogger(DubboZKSpringProvider.class);
		
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("provider.xml");
		log.info("Server is ready.");
		try {
			System.in.read();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
  • 服务消费者

Spring配置文件consumer.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://dubbo.apache.org/schema/dubbo
                           http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

	<dubbo:application name="sample-consumer-sp"/>
	<dubbo:registry address="zookeeper://localhost:2181"/>
	<dubbo:reference id="userService" interface="dubbo.service.UserService"/>
</beans>

主程序:

package demo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import dubbo.model.User;
import dubbo.service.UserService;

public class DubboZKSpringConsumer {

	public static void main(String[] args) {
		Logger log = LoggerFactory.getLogger(DubboZKSpringConsumer.class);
		//同一台机器上启动多个dubbo应用QoS服务端口会冲突,需要修改
		System.setProperty("dubbo.application.qos.port", "22223");
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("consumer.xml");
		UserService userService = (UserService) context.getBean("userService");
		User user = userService.getUser(1);
		log.info(user.toString());
	}
}

4、使用SpringBoot和nacos

  • nacos

启动nacos(单机模式):

startup.cmd -m standalone
  • 服务提供者

继承及依赖:

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.7.18</version>
</parent>

<dependencies>
	<!-- Spring Boot Web 起步依赖:包含了开发 Web 应用所需的几乎所有依赖(如 Spring MVC, Tomcat) -->
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	
	<dependency>
		<groupId>org.apache.dubbo</groupId>
		<artifactId>dubbo-spring-boot-starter</artifactId>
		<version>2.7.4.1</version>
	</dependency>
	
	<!-- zk客户端依赖:curator -->
	<dependency>
		<groupId>org.apache.curator</groupId>
		<artifactId>curator-recipes</artifactId>
		<version>5.5.0</version>
	</dependency>
	<dependency>
		<groupId>org.apache.curator</groupId>
		<artifactId>curator-framework</artifactId>
		<version>5.5.0</version>
	</dependency>
	
	<!-- Dubbo Nacos registry dependency -->
	<dependency>
		<groupId>org.apache.dubbo</groupId>
		<artifactId>dubbo-registry-nacos</artifactId>
		<version>2.7.17</version>
	</dependency>
</dependencies>

application.properties

server.port=6060
dubbo.application.name=dubbo-provider-sb
dubbo.registry.address=nacos://localhost:8848
dubbo.protocol.name=dubbo
dubbo.protocol.port=20990

服务实现类:

package server;

import org.apache.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;

import dubbo.model.User;
import dubbo.service.UserService;

@Service
@Component
public class UserServiceImpl implements UserService{

	@Override
	public User getUser(long id) {
		User user = new User();
		user.setId(id);
		user.setName("Jack");
		user.setSex("Man");
		return user;
	}

	@Override
	public void sayHi(String name) {
		System.out.println("~Hi, " + name);
	}
}

主程序:

package server;

import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@EnableDubbo
@SpringBootApplication
public class DubboSpringBootProvider {

	public static void main(String[] args) {
		SpringApplication.run(DubboSpringBootProvider.class, args);
	}
}
  • 服务消费者

继承及依赖同服务提供者。

application.properties

server.port=7070
dubbo.application.name=dubbo-consumer-sb
dubbo.registry.address=nacos://localhost:8848

应用启动后执行的Runner:

package client;

import org.apache.dubbo.config.annotation.Reference;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import dubbo.model.User;
import dubbo.service.UserService;

@Component
public class MyStartupRunner implements ApplicationRunner{

	@Reference
	private UserService service;
	
	@Override
	public void run(ApplicationArguments args) throws Exception {
		User user = service.getUser(1);
		System.out.println(user);
		service.sayHi(user.getName());
	}

}

主程序:

package client;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DubboSpringBootConsumer {

	public static void main(String[] args) {
		SpringApplication.run(DubboSpringBootConsumer.class, args);
	}
	
}
参考资料