王富贵

Stay hungry,Stay foolish

若你自认理性且正确,那更应该心平气和,言之有据地与人交流,即使不能立刻说服对方,但也至少埋下了一颗种子,冷嘲热讽或居高临下的态度,总会加大人与人之间的隔阂,最终只是在自己的小圈子中制造回声。愿我们最终都能成为乐观且包容的人,愿意耐心听取他人的苦衷和心声。
  menu
69 文章
0 浏览
0 当前访客
ღゝ◡╹)ノ❤️

Dubbo3入门

1、Dubbo3入门

本文章使用2022年9月Dubbo3.1.1版本。如果时过迁境,本篇文章经供参考。

学习Dubbo需要部分微服务思想,nacos相关知识,以及可能需要docker-conpose将nacos跑起来。

1.1、什么是Dubbo

dubbo java 官方文档

Apache Dubbo 是一款 RPC 微服务框架,提供了包括 Java、Golang 等在内的多种语言 SDK 实现。使用 Dubbo 开发的微服务原生具备相互之间的远程地址发现与通信能力, 利用 Dubbo 提供的丰富服务治理特性,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。Dubbo 被设计为高度可扩展,用户可以方便的实现流量拦截、选址的各种定制逻辑。

Dubbo和OpenFeign有什么区别?

Dubbo比OpenFeign更加的灵活,功能集成度更高,虽然后续OpenFeign增加了更多的远程调用协议和序列化协议。但Dubbo还拥有原生的服务发现,负载均衡,流量调度等功能。同时,他的架构复杂度比OpenFeign更高,因此对未来协议的适配程度更高,二次开发灵活度也更高。并且,Dubbo也在做云原生的一些事情。

1.2、体验Dubbo

我们以SpringBoot为例,简单去体验一下Dubbo3的使用。

强烈建议你使用jdk8,不然需要解决一个麻烦的反射报错。

如果你只想得到测试demo,那么可以访问:hy-dubbo-demo项目地址

1.2.1、先知

由于Dubbo的版本是强依赖性的,因此建议与我版本高度一致。

  1. jdk8
  2. nacos2.1.1
  3. dubbo3.1.1

明确Dubbo远程调用要做的事情

  1. 添加Dubbo核心依赖
  2. 添加要使用的注册中心与Dubbo整合的依赖
  3. 添加要使用的协议依赖
  4. 配置Dubbo基本信息

1.2.2、公用包准备

公用包一般来说是去包含远程调用过程中的接口和实体类。

1.服务提供方对接口进行实现后,我们服务调用方需要注入接口,才能知晓具体调用的是哪个服务。因此双方都必须明确接口。

有个小细节,服务提供者是对接口进行实现并注册到注册中心中的,而服务消费者是直接使用接口进行注入,这属于DI的内容,也可以理解为高级多态(父类的引用指向子类的实现)。

2.实体类在Dubbo远程调用国产中需要双方序列化,因此必须实现 Serializable 序列化接口 ,否则会报错

1.项目结构

1

2.pom依赖

我们只需要实体类的一些get和set方法即可,引入lombok就行

<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.24</version>
    </dependency>
</dependencies>

3.pojo

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
    private Integer id;
    private String username;
}

4.Service

public interface UserService {
    User getUser(Integer id);
}

1.2.3、服务提供方

当然,在这个环节,我们就需要跑一个注册中心了,我使用的是nacos2.1.1。

1.项目结构

2

2.pom依赖

由于我们dubbo使用的是3.1.1版本,所以相关的spring-boot依赖,rpc协议依赖和Dubbo注册中心依赖均使用3.1.1版本。请你注意,一般Spring,SpringBoot,注册中心,Dubbo这一系列的中间件都是配套的,因此他们的版本号最好使用官方推荐的。spring-cloud-alibaba中文组件说明

当然,我这里使用的是最新版本,也只是测试环境下使用。通常来讲以Dubbo版本为例,其他依赖包均为此版本。

<dependencies>
    <!-- 引入公用包 -->
    <dependency>
        <groupId>com.hy</groupId>
        <artifactId>common</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>

    <!-- springboot的一些依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!--Dubbo的相关依赖-->
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
        <version>3.1.1</version>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-rpc-dubbo</artifactId>
        <version>3.1.1</version>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-registry-nacos</artifactId>
        <version>3.1.1</version>
    </dependency>

</dependencies>

3.启动类

启动类需要使用 @EnableDubbo 注解来声明我们开启Dubbo。

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

}

4.Service

对于服务提供方而言,我们需要使用 @DubboService注解,作用是将此Service作为一个服务在注册中心中注册。

@DubboService
public class UserServiceImpl implements UserService {
    @Override
    public User getUser(Integer id) {
        return new User(id, "坏银");
    }

}

5.配置文件

Dubbo nacos配置文档

在配置文件中,我们主要是配置应用名,以及注册中心的一些相关配置。对于nacos而言,则是命名空间,分组,地址,用户名,密码等等。这里为了减少负担,大多都采用默认配置类。

server:
  port: 9200
spring:
  application:
    name: dubbo-provider

dubbo:
  application:
    name: hy-dubbo-provider
  registry:
    address: nacos://localhost:8848
    username: nacos
    password: nacos

1.2.4、服务消费方

1.项目结构

3

2.pom依赖

与服务提供方一致

<dependencies>
    <!-- 引入公用包 -->
    <dependency>
        <groupId>com.hy</groupId>
        <artifactId>common</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>

    <!-- springboot的一些依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!--Dubbo的相关依赖-->
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
        <version>3.1.1</version>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-rpc-dubbo</artifactId>
        <version>3.1.1</version>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-registry-nacos</artifactId>
        <version>3.1.1</version>
    </dependency>

</dependencies>

3.Serice

在服务消费方,我们需要调用服务提供方的接口,我们只需要使用 @DubboReference 装配接口即可。Dubbo会自己将远程调用,负载均衡,序列化等等过程解决的。不需要我们手动解决。这也是Dubbo的亮点,远程调用像本地调用一样简单。

@Service
public class OrderService {
    @DubboReference
    private UserService userService;

    public String createOrder() {
        User user = userService.getUser(6905);
        System.out.println("成功创建订单");

        return user.toString() + "已经成功为用户创建订单";
    }
}

4.配置文件

此处的配置文件配置的内容与服务提供方无异。

server:
  port: 9201

spring:
  application:
    name: dubbo-consumer

dubbo:
  protocol:
    host: 127.0.0.1
  application:
    name: hy-dubbo-consumer
  registry:
    address: nacos://localhost:8848
    username: nacos
    password: nacos

tips:

服务消费方主启动类上可以不使用@EnableDubbo注解

服务消费方默认是不在注册中心注册的

1.2.5、报错问题

1.反射报错

如果你使用的是jdk8以上,大概率会报反射错误,我们需要在java的运行环境上加上:

--illegal-access=deny
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/sun.net.util=ALL-UNNAMED
--add-opens java.base/java.math=ALL-UNNAMED

4

2.实体类未实现序列化接口

如果你的公用实体类没有实现 Serializable 接口,那么在远程调用过程中使用了该实体,必然报错。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
    private Integer id;
    private String username;
}

1.3、Dubbo使用说明

实际上,Dubbo的使用是非常简单的。步骤如下:

  1. 定义服务接口
  2. 配置Dubbo配置文件,配置中心,序列化,网络协议等等
  3. 服务提供方暴露接口,可以使用 DubboService
  4. 服务提供方定义Spring Boot主函数,可以使用 @EnableDubbo
  5. 服务消费方调用远程服务即可, DubboReference

Dubbo 抽象了一系列的结构化配置,对不同的用户而言,既可以以最小化配置快速启动服务,又可以在需要时通过复杂的配置精确的控制服务行为; 除了 API + Properties 的基本使用方式之外,通过与 Spring 的集成 Dubbo 在配置形式上还支持 SpringBoot、Annotation、XML、YAML 等。

Dubbo 配置参考手册

因此,我们上述使用的流程是常用且便捷的流程,但并不代表非他不可。

1.4、Dubbo原理

1.5、Dubbo3新特性

Dubbo3.0速览

Dubbo3有几个很重要的新特性

  • 应用级服务发现
  • Triple,自研通信协议
  • 跨语言调用
  • Dubbo Mesh

1.5.1、应用级服务发现

应用级的服务发现,实际上是注册模型的改变。在服务注册领域中,市面上有两种常见的模型,一种是应用级注册,一种是接口级注册。在Spring Cloud中,一个应用就是一个微服务。而在Dubbo2中,一个接口就会被注册成为一个微服务。Dubbo3优化了注册模型,将Dubbo2的接口级注册转变成为Dubbo3的应用级注册。

官方文档:Dubbo3的服务发现

官方文档:Dubbo2和Dubbo3在Nacos中的注册数据

我们以官方文档的图,来对比一下

1.Dubbo2

下面是nacos1中的注册实例,如果你点开观察注册元数据,就会发现他是一个接口,也就是一个方法就注册一个数据。

使用@DubboService注解下的每个方法都注册一个应用

5

6

2.Dubbo3

而对于Dubbo3和Nacos2中,他是以应用名来进行注册的。并且同时也会注册这个应用的实例。

Dubbo3 默认采用 “应用级服务发现 + 接口级服务发现” 的双注册模式,因此会发现应用级服务(应用名)和接口级服务(接口名)同时出现在 Nacos 控制台,可以通过配置 dubbo.registry.register-mode=instance/interface/all 来改变注册行为。

笼统的来说就是,将@DubboService注解下的Service注册成一个应用,并且还会将此jar包运行包注册成为一个应用。

7

Dubbo3 服务发现模型更适合构建可伸缩的服务体系,这点要如何理解? 这里先举个简单的例子,来直观的对比 Dubbo2 与 Dubbo3 在地址发现流程上的数据流量变化:假设一个微服务应用定义了 100 个接口(Dubbo 中的服务), 则需要往注册中心中注册 100 个服务,如果这个应用被部署在了 100 台机器上,那这 100 个服务总共会产生 100 * 100 = 10000 个虚拟节点;而同样的应用, 对于 Dubbo3 来说,新的注册发现模型只需要 1 个服务(只和应用有关和接口无关), 只注册和机器实例数相等的 1 * 100 = 100 个虚拟节点到注册中心。 在这个简单的示例中,Dubbo 所注册的地址数量下降到了原来的 1 / 100,对于注册中心、订阅方的存储压力都是一个极大的释放。更重要的是, 地址发现容量彻底与业务 RPC 定义解耦开来,整个集群的容量评估对运维来说将变得更加透明:部署多少台机器就会有多大负载,不会像 Dubbo2 一样, 因为业务 RPC 重构就会影响到整个集群服务发现的稳定性。

1.5.2、Triple(新一代RPC通信协议)

Triple 是 Dubbo3 提出的基于 HTTP2 的开放协议,旨在解决 Dubbo2 私有协议带来的互通性问题。他完全兼容gRPC协议(实现差不多,可以认为是两兄弟),并在此基础上拓展出更丰富的语义。相比于原有 Dubbo2 协议,Triple 有以下优势:

  1. 原生和 gRPC 协议互通。打通 gRPC 生态,降低从 gRPC 至 Dubbo 的迁移成本。
  2. 增强多语言生态。避免因 CPP/C#/RUST 等语言的 Dubbo SDK 能力不足导致业务难以选型适配的问题。
  3. 网关友好。网关无需参与序列化,方便用户从传统的 HTTP 转泛化 Dubbo 调用网关升级至开源或云厂商的 Ingress 方案。
  4. 完善的异步和流式支持。带来从底层协议到上层业务的性能提升,易于构建全链路异步以及严格保证消息顺序的流式服务。

我们可以具体了解一下为啥叫网关友好。

在传统微服务中,用户一般是使用http请求调用服务的,http请求网关后,由网关进行转发请求,实际上转发的过程是网关进行gRPC调用微服务接口的过程。那么网关需要将http请求体,转化成为gRPC请求进行调用的,这个过程性能损耗比较大。

而使用Triple协议,网关依然是需要转化的,他是Http2.0实现的,并且也兼容gRPC协议,因此网关转化的代价很小,性能也就更高的。

网关转化的代价主要是什么?主要是做了一个无用的序列化和反序列化操作。由于gRPC与http不互通,因此网关需要将Http请求反序列化,然后再序列化为gRPC识别的序列化方式。而Triple由于同时兼容Http和gRPC,因此不需要网关进行中间过程的序列化。

8

1、体验Triple

我们可以来体验一下使用Triple的新特性,依然使用之前的项目

对于模块而言,我们需要两个步骤。

  1. 引入Triple协议包
  2. 配置文件声明使用Triple协议

1.引入Triple协议包,注意与你Dubbo版本一致

<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-rpc-triple</artifactId>
    <version>3.1.1</version>
</dependency>

2.配置文件声明使用Triple协议

dubbo.protocol.name = "tri" # tri就代表使用Triple,约定大于配置

我们可以只需要在服务提供方配置,因为注册的时候注册中心元数据会声明请求类型的,服务消费方只需要引入了Triple协议包就可以自己去调用。

事实上,通过修改上述配置,服务提供方已经将元数据请求协议修改为Triple协议,而服务调用方拿到服务提供元数据,发现调用方法为Triple协议时,就会自己使用对于的协议进行调用。我们只需要引入该协议相关的maven包即可。

nacos中的注册元数据

9

2、流式调用

Stream 是 Dubbo3 新提供的一种调用类型,简单来说就是一个方法体内可以多次请求与响应,在以下场景时建议使用流的方式:

  • 接口需要发送大量数据,这些数据无法被放在一个 RPC 的请求或响应中,需要分批发送,但应用层如果按照传统的多次 RPC 方式无法解决顺序和性能的问题,如果需要保证有序,则只能串行发送
  • 流式场景,数据需要按照发送顺序处理, 数据本身是没有确定边界的
  • 推送类场景,多个消息在同一个调用的上下文中被发送和处理

他的主要原理就是依赖于使用了http2.0的Triple协议,其特点为长连接,全双工。

流的语义保证

  • 提供消息边界,可以方便地对消息单独处理
  • 严格有序,发送端的顺序和接收端顺序一致
  • 全双工,发送不需要等待
  • 支持取消和超时

流的调用有三种

  • SERVER_STREAM(服务端流)
  • CLIENT_STREAM(客户端流)
  • BIDIRECTIONAL_STREAM(双向流)

在使用之前,我们再次提醒这是Triple协议的内容,因此需要我们在配置文件中声明使用Triple协议,因为Dubbo3.1.1版本默认使用的并不是Triple协议

2.1、unary(正常模式)

unary就是正常Dubbo调用的模式,不包括在流式调用里面

公用common接口

public interface UserService {
    User getUser(Integer id);  
}

服务提供方实现接口并注入

@DubboService
public class UserServiceImpl implements UserService {
    @Override
    public User getUser(Integer id) {
        return new User(id, "坏银");
    }
}

服务消费方,注入接口并调用对应方法即可

@Service
public class OrderService {
    @DubboReference
    private UserService userService;

    public String createOrder() {
        User user = userService.getUser(6905);
        System.out.println("成功创建订单");

        return user.toString() + "已经成功为用户创建订单";
    }
}
2.2、server-stream(服务端流)

服务端流的意思就是服务端(生产者)能够不停的向请求端(消费者)响应数据,而不是单纯的调用一次。

10

1.common包引入依赖

服务端流也就是我们服务提供方,由于服务提供和消费都以common公用包的接口为媒介,所以我们在common包需要引入 dubbo-common 包才能使对应的实体。

<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-common</artifactId>
    <version>3.1.1</version>
</dependency>

2.接口实现服务端流方法,common包下的共用接口

public interface UserService {
    //server-stream 服务端流,返回类型和参数校验不能出错
    void sayHelloServerStream(String name, StreamObserver<String> response);
}

3.服务提供方(生产者)重写该方法,进行多次响应

@DubboService
@Override
public void sayHelloServerStream(String name, StreamObserver<String> response) {
    // 循环响应信息,建立长连接,而不是调用一次
    for (int i = 0; i < 10; i++) {
        response.onNext("hello," + name);
    }

    // 响应完成,结束方法
    response.onCompleted();
}

4.服务消费方,实现序列化接口,注入对应的接口,进行对应方法的调用即可。

@Service
public class OrderService implements Serializable{
    @DubboReference
    private UserService userService;

    //进行服务端流的消费
    public String getResponse(){
        //服务端流,消费方不停的接收响应
        userService.sayHelloServerStream("hello", new StreamObserver<String>() {
            //接收响应处理程序
            @Override
            public void onNext(String data) {
                System.out.println("接受到结果:"+data);
            }

            //接收错误处理程序
            @Override
            public void onError(Throwable throwable) {
                System.out.println("服务提供方报错了");
            }

            //接收完成处理参数
            @Override
            public void onCompleted() {
                System.out.println("服务端响应结束,现在是我接收端");
            }
        });

        return "";
    }
}

tips:

我们一定要注意的细节是消费方的Service实现了 Serializable 接口,也就是说这个接口需要序列化。实际上,服务端流接收消息是需要序列化消费端接口的远程调用的,调用的是匿名内部类的三个方法,而三个方法是匿名的,因此我们只能对外部的Service实现序列化接口,进而内部匿名内部类能够序列化。

2.3、client-stream(客户端流)、bi-stream(双向流)

我们的客户端流和双向流实际上是一个实现方式,这是由于 java 语言的限制。

那么客户端流也就是服务消费者不停的请求服务提供者,当然由于他和双向流共同实现,因此也是支持双工消费的。

具体流程如下

1.引入common包,之前我们已经引入过来

2.接口实现客户端流方法,common包下的共用接口

不难发现,这个方法多了返回值,那么这个返回值就是response,通过他就能够实现互相通行

public interface UserService {
    //client-stream 客户端流 / bidirectional-stream 双向流
    StreamObserver<String> sayHelloStream(StreamObserver<String> response);
}

3.服务提供方(生产者)重写该方法,进行多次响应和请求

@DubboService
public class UserServiceImpl implements UserService {
    @Override
    public StreamObserver<String> sayHelloStream(StreamObserver<String> response) {
        return new StreamObserver<String>() {

            //想要流接收消息方法
            @Override
            public void onNext(String data) {
                System.out.println(data);
                response.onNext("hello,"+data);
            }

            // 响应流错误执行方法
            @Override
            public void onError(Throwable throwable) {
                throwable.printStackTrace();
            }

            // 响应流完成方法
            @Override
            public void onCompleted() {
                System.out.println("onCompleted");
                response.onCompleted();
            }
        };
    }
}

4.服务消费方(消费者)注入这个Dubbo接口,调用方法

@Service
public class OrderService implements Serializable {
    @DubboReference
    private UserService userService;

    public StreamObserver<String> getStreamData() {

        //接收流式响应
        StreamObserver<String> request = userService.sayHelloStream(new StreamObserver<String>() {
            @Override
            public void onNext(String data) {
                System.out.println(data);
            }

            @Override
            public void onError(Throwable throwable) {
                throwable.printStackTrace();
            }

            @Override
            public void onCompleted() {
                System.out.println("终止请求");
            }
        });

        //再次请求
        for (int i = 0; i < 10; i++) {
            request.onNext("消费方请求" + i);
        }

        //终止连接
        request.onCompleted();

        return request;
    }
}

1.5.3、跨语言调用

官方文档:IDL 定义跨语言服务

在使用Dubbo的微服务开发中,服务生产者与服务消费者使用common(公共包)下的接口和实体来实现。他们在远程调用的过程中一个提供方法名,一个提供序列化与反序列化实体媒介。实际上他们在网络上传输的都是二进制文件,因此理论上来说是能够实现跨语言调用的。

当然,如果我们需要使用跨语言调用,那么common包的接口和实体,必须二者语言都能够序列化并实现。而不是单方的实现。

假如消费者不是用java语言写的,那至少满足一下条件才能够调用java实现的Dubbo服务

  1. Dubbo一开始是用Java语言实现的,那现在就需要一个go语言实现的Dubbo框架,也就是现在的dubbo-go,然后在go项目中引入dubbo-go,从而可以在go项目中使用dubbo,比如使用go语言去暴露和使用Dubbo服务。
  2. 我们在使用Java语言开发一个Dubbo服务时,会把服务接口和相关类,单独抽象成为一个Maven项目,实际上就相当于一个单独的jar包,这个jar能被Java项目所使用,但不能被go项目所使用,所以go项目中该如何使用Java语言所定义的接口呢?直接用是不太可能的,只能通过间接的方式来解决这个问题,除开Java语言之外,那有没有其他技术也能定义接口呢?并且该技术也是Java和go都支持,这就是protobuf。

因此,protobuf是多种语言的媒介,通过protobuf编译器,能够将接口和实体编译为特定语言的接口和实体。以此来实现不同语言common包的所需的接口和实体。

1.使用protobuf

使用 IDL 定义服务具有更好的跨语言友好性,对于 Dubbo3 新用户而言,我们推荐使用这种方式。 然而 Triple 协议并不是和 IDL 强绑定的,也可以使用 Java Interface + Pojo 的方式定义服务并启用 Triple 协议。Dubbo 使用 Protobuf 作为 IDL。

1.创建一个dubbo-IDL-common的普通maven项目,我们可以使用这个项目直接当作common包

请千万注意,我们需要使用maven的complie将porto文件编译成java,因此需要读取路径文件,请务必保证路径下没有中文

11

2.在项目中定义proto文件,可以叫做 userservice.proto ,路径为 src/main/proto/uservice.porto ,这里要注意proto文件一定要放在该路径下才能够读取到。

那么这个文件就是我们定义接口和实体的细节了。相当于定义了一个HelloService服务,并且定义了一个getUser方法,接收UserRequest类型的参数,返回User类型的对象。

syntax = "proto3";

package api;

// go包前缀
option go_package = "./;api";

option java_multiple_files = true;
// java包前缀
option java_package = "com.hy";
// java外部类名
option java_outer_classname = "UserServiceProto";

// 定义接口
service UserService {
  // 调用方法,方法名,返回
  rpc GetUser (UserRequest) returns (User) {}
}

// 定义实体
message UserRequest {
  string uid = 1;
}

message User {
  string uid = 1;
  string username = 2;
}

3.编译成java

在项目的pom文件中添加相关的依赖以及构建插件

<dependencies>
    <!-- protobuf java对应包 -->
    <dependency>
        <groupId>com.google.protobuf</groupId>
        <artifactId>protobuf-java</artifactId>
        <version>3.21.6</version>
    </dependency>

    <!-- dubbo包 -->
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo</artifactId>
        <version>3.1.1</version>
    </dependency>
</dependencies>

<build>
    <extensions>
        <extension>
            <groupId>kr.motd.maven</groupId>
            <artifactId>os-maven-plugin</artifactId>
            <version>1.6.1</version>
        </extension>
    </extensions>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.7.0</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.xolstice.maven.plugins</groupId>
            <artifactId>protobuf-maven-plugin</artifactId>
            <version>0.6.1</version>
            <configuration>
                <protocArtifact>com.google.protobuf:protoc:3.7.1:exe:${os.detected.classifier}</protocArtifact>
                <!-- 最后输出路径,还会加上proto配置的包名,我的就是com/hy -->
                <outputDirectory>src/main/java</outputDirectory>
                <clearOutputDirectory>false</clearOutputDirectory>
                <protocPlugins>
                    <protocPlugin>
                        <id>dubbo</id>
                        <groupId>org.apache.dubbo</groupId>
                        <artifactId>dubbo-compiler</artifactId>
                        <version>0.0.3</version>
                        <mainClass>org.apache.dubbo.gen.dubbo.Dubbo3Generator</mainClass>
                    </protocPlugin>
                </protocPlugins>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <goal>test-compile</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>build-helper-maven-plugin</artifactId>
            <version>3.0.0</version>
            <executions>
                <execution>
                    <phase>generate-sources</phase>
                    <goals>
                        <goal>add-source</goal>
                    </goals>
                    <configuration>
                        <sources>
                            <source>src/main/java</source>
                        </sources>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

然后运行provider中lifecycle的compile,就会进行编译了

12

并且会编译出对应的接口等信息,编译完成后,会生成一些类:

13

其中就包括了一个UserService接口,所以我们的UserServiceImpl就可以实现这个接口了:

@DubboService
public class UserServiceImpl implements UserService {

    public User getUser(UserRequest userRequest) {
        User user = User.newBuilder().setUid(userRequest.getUid()).setUsername("hy").build();
        return user;
    }

}

而对于想要调用UserService服务的消费者而言,其实也是一样的改造,只需要使用同一份userservice.proto进行编译就可以了,比如现在有一个go语言的消费者。

2.go语言编译

go语言暂时我们就不做展示了


标题:Dubbo3入门
作者:1938857445
地址:https://www.lmlx66.top/articles/2022/10/07/1665149587304.html