使用原生 API 开发 Dubbo 应用

作为一款 RPC 框架,Dubbo 定义了一套完善的 API 接口,我们可以基于原生 API 开发 RPC 服务和微服务应用

你可能已经注意到了,文档中大部分的功能、示例都是基于 Spring Boot 模式编写的,但 Spring Boot 或 Spring 仅仅是 Dubbo 适配的一种应用或者微服务开发模式。作为一款 RPC 框架,Dubbo 定义了一套完善的 API 接口,我们可以基于原生 API 开发 Dubbo 应用,纯 API 可以实现的业务场景包括:

  • 轻量 RPC Server & Client,通常用于一些应用内、基础组件、中间件等内的简单远程调用场景
  • 微服务应用,不依赖 Spring 的情况下,直接用 API 开发微服务

API 概览

  1. public class Application {
  2. public static void main(String[] args) {
  3. DubboBootstrap.getInstance()
  4. .protocol(new ProtocolConfig(CommonConstants.TRIPLE, 50051))
  5. .service(ServiceBuilder.newBuilder().interfaceClass(DemoService.class).ref(new DemoServiceImpl()).build())
  6. .start()
  7. .await();
  8. }
  9. }

以上是启动 Dubbo RPC Server 的一段代码示例,DubboBootstrap 实例代表一个 Dubbo 应用,是整个 Dubbo 应用的启动入口。在 DubboBootstrap 基础上,我们可以设置 protocolserviceregistrymetrics 等来注册服务、连接注册中心等,这和我们在 Spring Boot 中调整 application.yml 或者 application.properties 文件是对等的作用。

官方推荐使用 DubboBootstrap.start() 作为应用的集中启动入口,但为了方便在进程启动后,在运行态单独发布一些服务,Dubbo 框架也允许直接调用 ServiceConfig.export()ReferenceConfig.refer() 方法发布单个服务,这时 Service/Reference 会注册到默认的 DubboBootstrap 实例中,效果同调用 DubboBootstrap.service(...).start() 类似。

以下是开发中会常用到的一些组件,完整组件定义及详细参数说明请参见 参考手册 - 配置项手册

API 组件全局唯一核心方法或属性说明
DubboBootstrap是(多应用场景除外)start()、stop()DubboBootstrap 实例代表一个 Dubbo 应用,是整个 Dubbo 应用的启动入口。
ApplicationConfigname应用名及应用级别的一些全局配置
MetricsConfigprotocol、prometheus、tracingMetrics、tracing 采集相关配置
ProtocolConfig否。多协议场景服务通过 id 关联id、name、port、serialization、threadpoolRPC 协议端口、序列化协议、运行时行为配置
RegistrtyConfig否。多注册中心场景服务通过 id 关联id、address、protocol、group注册中心实现、地址、订阅等配置
ConfigCenterConfig否。多配置中心场景服务通过 id 关联id、address、protocol、group、namespace配置中心实现、地址、分组隔离等配置
MetadataReportConfig否。多元数据中心场景服务通过 id 关联id、address、protocol、group、namespace元数据中心实现、地址、分组隔离等配置
ProviderConfig参考 ServiceConfig作为多个ServiceConfig的默认值
ConsumerConfig参考 ReferenceConfig作为多个ReferenceConfig的默认值
ServiceConfig- 方法:export()
- 属性: interfaceClass、ref、group、version、timeout、retry
一个 ServiceConfig 实例代表一个 RPC 服务
ReferenceConfig- 方法:refer()
- 属性:interfaceClass、group、version、timeout、retry、cluster、loadbalance
一个 ReferenceConfig 实例代表一个 RPC 服务
MethodConfigname、oninvoke、onreturn、onthrowServiceConfig/ReferenceConfig 内嵌的方法级别配置
ArgumentConfigindex、type、callbackMethodConfig 内嵌的参数级别配置

轻量 RPC 示例

本示例演示如何使用轻量 Dubbo SDK 开发 RPC Server 与 Client,示例使用 Java Interface 方式定义、发布和访问 RPC 服务,底层使用 Triple 协议通信。本示例完整代码请参见 dubbo-samples

基于 Dubbo 定义的 Triple 协议,你可以轻松编写浏览器、gRPC 兼容的 RPC 服务,并让这些服务同时运行在 HTTP/1 和 HTTP/2 上。Dubbo Java SDK 支持使用 IDL 或编程语言特有的方式定义服务,并提供一套轻量的 API 来发布或调用这些服务。

Maven 依赖

在基于 Dubbo RPC 编码之前,您只需要在项目添加一个非常轻量的 dubbo依赖包即可,以 Maven 为例:

  1. <dependency>
  2. <groupId>org.apache.dubbo</groupId>
  3. <artifactId>dubbo</artifactId>
  4. <version>3.3.0</version>
  5. </dependency>

定义服务

定义一个名为 DemoService的标准 Java 接口作为 Dubbo 服务(Dubbo 还支持基于 IDL 的服务定义模式)。

  1. public interface DemoService {
  2. String sayHello(String name);
  3. }

实现 DemoService 接口并编写业务逻辑代码。

  1. public class DemoServiceImpl implements DemoService {
  2. @Override
  3. public String sayHello(String name) {
  4. return "Hello " + name + ", response from provider.";
  5. }
  6. }

注册服务并启动 Server

启动 server 并在指定端口监听 RPC 请求,在此之前,我们向 server 注册了以下信息:

  • 使用 Triple 作为通信 RPC 协议与并监听端口 50051
  • 注册 Dubbo 服务到 DemoService server
  1. public class Application {
  2. public static void main(String[] args) {
  3. DubboBootstrap.getInstance()
  4. .protocol(new ProtocolConfig(CommonConstants.TRIPLE, 50051))
  5. .service(ServiceBuilder.newBuilder().interfaceClass(DemoService.class).ref(new DemoServiceImpl()).build())
  6. .start()
  7. .await();
  8. }
  9. }

访问服务

最简单方式是使用 HTTP/1.1 POST 请求访问服务,参数则以标准 JSON 格式作为 HTTP 负载传递。如下是使用 cURL 命令的访问示例:

  1. curl \
  2. --header "Content-Type: application/json" \
  3. --data '["Dubbo"]' \
  4. http://localhost:50051/org.apache.dubbo.demo.DemoService/sayHello

参数必须以数组格式进行传递,如果有多个参数,则格式类似 ["param1", {"param2-field": "param2-value"}, ...],具体请参见 triple 协议规范。

接下来,您也可以使用标准的 Dubbo client 请求服务,指定 server 地址即可发起 RPC 调用,其格式为 protocol://ip:host

  1. public class Application {
  2. public static void main(String[] args) {
  3. DemoService demoService =
  4. ReferenceBuilder.newBuilder()
  5. .interfaceClass(DemoService.class)
  6. .url("tri://localhost:50051")
  7. .build()
  8. .get();
  9. String message = demoService.sayHello("dubbo");
  10. System.out.println(message);
  11. }
  12. }

恭喜您, 以上即是 Dubbo Java RPC 通信的基本使用方式! 🎉

更多示例

除了以上简单使用场景之外,开发者还可以发布多个服务、直接调用 ServiceConfig/ReferenceConfig 发布/订阅单个服务等。

发布多个服务

以下示例注册并发布任意多个服务 FooService、BarService,这些服务都将使用 providerConfig 中配置的默认超时时间,省去多个服务重复配置的烦恼。

  1. public static void main(String[] args) {
  2. ProviderConfig providerConfig = new ProviderConfig();
  3. providerConfig.setTimeout(5000);
  4. ProtocolConfig protocolConfig = new ProtocolConfig(CommonConstants.TRIPLE, 50051);
  5. DubboBootstrap.getInstance()
  6. .protocol(protocolConfig)
  7. .provider(providerConfig)
  8. .service(ServiceBuilder.newBuilder().interfaceClass(FooService.class).ref(new FooServiceImpl()).build())
  9. .service(ServiceBuilder.newBuilder().interfaceClass(BarService.class).ref(new BarServiceImpl()).build())
  10. .start()
  11. .await();
  12. }

发布单个服务

直接调用 ServiceConfig.export() 发布服务,适用于运行态动态发布或订阅一个服务,对于 ReferenceConfig 同理。对于正常的应用启动流程,推荐使用 DubboBootstrap 而非直接调用 ServiceConfig.export() 发布单个服务。

  1. 通过 ServiceConfig 发布服务
  1. public static void main(String[] args) {
  2. ServiceConfig<DemoService> demoServiceConfig = new ServiceConfig<>();
  3. demoServiceConfig.setInterface(DemoService.class);
  4. demoServiceConfig.setRef(new DemoServiceImpl());
  5. demoServiceConfig.setVersion("1.0.0");
  6. demoServiceConfig.export(); // this service will be registered to the default instance of DubboBootstrap.getInstance()
  7. }
  1. 通过 ReferenceConfig 订阅服务
  1. private DemoService referService() {
  2. ReferenceConfig<DemoService> reference = new ReferenceConfig<>();
  3. reference.setInterfaceClass(DemoService.class);
  4. ReferenceCache cache = SimpleReferenceCache.getCache();
  5. try {
  6. return cache.get(reference);
  7. } catch (Exception e) {
  8. throw new RuntimeException(e.getMessage());
  9. }
  10. }

由于 ReferenceConfig.get() 创建的代理对象持有连接、地址等大量资源,因此建议缓存复用,Dubbo 官方提供了 SimpleReferenceCache 实现参考实现。关于 SimpleReferenceCache 更多内容,请参考 RPC 框架

获得引用代理

使用 DubboBootstrap 作为启动入口,订阅服务并获得代理对象。

  1. public static void main(String[] args) {
  2. ReferenceConfig<GreetingsService> reference =
  3. ReferenceBuilder.<GreetingsService>newBuilder()
  4. .interfaceClass(GreetingsService.class)
  5. .build();
  6. DubboBootstrap.getInstance().reference(reference).start();
  7. GreetingsService service = reference.get();
  8. }

微服务示例

注册中心和应用名

相比于 RPC server、RPC client,基于 API 的微服务应用开发需要配置应用名、注册中心。

  1. public static void main(String[] args) {
  2. DubboBootstrap.getInstance()
  3. .application()
  4. .registry(new RegistryConfig("nacos://127.0.0.1:8848"))
  5. .protocol(new ProtocolConfig(CommonConstants.TRIPLE, 50051))
  6. .service(ServiceBuilder.newBuilder().interfaceClass(DemoService.class).ref(new DemoServiceImpl()).build())
  7. .service(ServiceBuilder.newBuilder().interfaceClass(FooService.class).ref(new FooServiceImpl()).build())
  8. .start()
  9. .await();
  10. }

多个注册中心

多个注册中心可指定不同的 id,服务通过 id 关联注册中心实例。如下示例中,GreetingsService 发布到 bjRegistry,DemoService 发布到 hzRegistry。

  1. public static void main(String[] args) {
  2. RegistryConfig bjRegistry = new RegistryConfig();
  3. bjRegistry.setId("bj");
  4. bjRegistry.setAddress("nacos://127.0.0.1:8848");
  5. RegistryConfig hzRegistry = new RegistryConfig();
  6. hzRegistry.setId("hz");
  7. hzRegistry.setAddress("nacos://127.0.0.2:8848");
  8. DubboBootstrap.getInstance()
  9. .registry(bjRegistry)
  10. .registry(hzRegistry)
  11. .service(ServiceBuilder.newBuilder().registryIds("bj").interfaceClass(GreetingsService.class).ref(new GreetingsServiceImpl()).build())
  12. .service(ServiceBuilder.newBuilder().registryIds("hz").interfaceClass(DemoService.class).ref(new DemoServiceImpl()).build())
  13. .start()
  14. .await();
  15. }

发布单个服务

直接调用 ServiceConfig.export() 发布服务,适用于运行态动态发布或订阅一个服务,对于 ReferenceConfig 同理。对于正常的应用启动流程,推荐使用 DubboBootstrap 而非直接调用 ServiceConfig.export() 发布单个服务。

注意

  1. 通过 ServiceConfig 发布服务
  1. public static void main(String[] args) {
  2. RegistryConfig hzRegistry = new RegistryConfig();
  3. hzRegistry.setId("hz");
  4. hzRegistry.setAddress("nacos://127.0.0.2:8848");
  5. ServiceConfig<DemoService> demoServiceConfig = new ServiceConfig<>();
  6. demoServiceConfig.setInterface(DemoService.class);
  7. demoServiceConfig.setRef(new DemoServiceImpl());
  8. demoServiceConfig.setVersion("1.0.0");
  9. demoServiceConfig.setRegistry(hzRegistry);
  10. demoServiceConfig.export(); // this service will be registered to the default instance of DubboBootstrap.getInstance()
  11. }
  1. 通过 ReferenceConfig 订阅服务
  1. private DemoService referService() {
  2. RegistryConfig hzRegistry = new RegistryConfig();
  3. hzRegistry.setId("hz");
  4. hzRegistry.setAddress("nacos://127.0.0.2:8848");
  5. ReferenceConfig<DemoService> reference = new ReferenceConfig<>();
  6. reference.setInterfaceClass(DemoService.class);
  7. reference.setRegistry(hzRegistry)
  8. ReferenceCache cache = SimpleReferenceCache.getCache();
  9. try {
  10. return cache.get(reference);
  11. } catch (Exception e) {
  12. throw new RuntimeException(e.getMessage());
  13. }
  14. }

更多内容

最后修改 October 22, 2024: fixed unspecified `interfaceClass` (#3052) (bcab21bd8a6)