【囫囵吞枣】如何初始化一个Spring Boot微服务项目 Part2 | 豆包MarsCode AI刷题

87 阅读3分钟

继续记录一下最近几天折腾的微服务小demo

3 微服务间通信:Protobuf

微服务之间通过传输消息来通信。按照如下语法定义消息:

message example {
    string myField = 1;
    int64 anotherField = 2;
    optional optionalField = 3;
    // 接着定义……
}

在上面的例子中:

  • 每一个Field都有唯一的编号,这个唯一指的是在一个message的定义里唯一。也就是说,定义两个message,example1和example2,这两个message里都可以有且仅有一个编号为1的字段。
  • 每个字段定义的语法是:<prefix> <type> <name> = <identifier>。具体有哪些type可以看ProtoBuf官网。
  • 有些时候爬取得到的数据并不是每个字段都有(比如TuShare……),这时我们可以为这样的字段设置optional关键字。

有时我们需要自己定义一些message里的字段类型。其实刚才定义的example字段就可以看作一种类型。

联系一下具体需求。假设有一个“基金净值查询”功能,查询某一段时间的特定基金的净值。不难想到,后端返回给前端的数据会长这样:

{
    "data": [
        {
            // 日期1的数据
        },
        {
            // 日期2的数据
        },
         // ...
    ]
}

写后端逻辑的时候,就是将很多基金净值存储到一个List里,然后再JSON序列化一下。那么如果用ProtoBuf,怎么定义一个消息里的“List”呢?这时就需要用到repeated关键字了。

/**
  基金净值
 */

message DomesticFundNavItem {
  string tsCode = 1;
  int64 annDate = 2;
  int64 navDate = 3;
  double unitNav = 4;
  double accumNav = 5;
  double accumDiv = 6;
  double netAsset = 7;
  double totalNetAsset = 8;
  double adjNav = 9;
}

message DomesticFundNavsByTsCodeAndDateRangeResponse {
  repeated DomesticFundNavItem items = 1;
}

在上面的例子中:

  • 我们定义了“基金单日净值”这一个message。
  • 我们定义了查询基金净值的Response message,注意微服务之间需要通过Protobuf序列化后的数据进行交流。
  • 在查询基金净值的Response message里,我们创建了一个必填的重复字段items,编号为1,并且items这个字段里可以有很多个DomesticFundNavItem。

定义完消息,我们就需要定义服务的具体输入和输出了,这样服务的调用者才能知道到底有哪些服务可以调用,怎么调用,并且服务的提供者才能知道具体要实现哪些服务。

回想在单体项目中,我们一般创建一个Service子包定义服务接口,然后再创建一个ServiceImpl子包进行具体的服务实现。但在微服务架构中,我们不可能为每个服务全部重复声明一遍所有的服务接口是什么,这样维护起来过于麻烦。

为此,我们可以新建一个包,这里就叫它interface。然后在interface包的main目录下,创建proto子文件夹,在其中编写每个服务所需要的消息和具体实现。

service DomesticFundService {

  rpc getDomesticFundInfoByTsCode(DomesticFundInfoByTsCodeRequest) returns (DomesticFundInfoByTsCodeResponse);
  rpc getDomesticFundNavsByTsCodeAndDateRange(DomesticFundNavsByTsCodeAndDateRangeRequest) returns (DomesticFundNavsByTsCodeAndDateRangeResponse);
  rpc searchFundInfo(DomesticFundSearchRequest) returns (DomesticFundSearchResponse);
}

上面的例子看起来可能让人头皮发麻,毕竟message的名称和服务的名称都太长了。简单来说:

  • 一般用rpc就行。
  • 服务定义方式为 <协议> <服务方法名称>(<入参>) returns (<出参>)

同时记得改pom.xml。具体怎么改放到下一篇文章吧,其实问问AI就行(