Java SDK的proto代码生成

介绍Dapr的Java SDK项目中的proto代码生成

dapr java sdk 仓库 clone下来代码之后,直接用IDE 如 IntelliJ 导入,是会报错的:有部分 dapr 的类找不到。这是因为这些代码是需要从 dapr 的 proto 代码中临时生成然后被项目装载。因此如果要进行 dapr java sdk 项目的开发或者代码阅读,需要从proto文件中生成这些类。

备注:

不同语言的sdk对生成代码的处理方式不同:

  • java sdk:采用的是不保存生成的代码到git仓库,每次需要的时候从proto文件生成,然后以 generated-sources 的方式被挂载到 mvn 项目中。
  • go sdk:有些语言的sdk如 go sdk,是将生成的代码直接提交到git仓库,这样如果不需要重新生成代码,是可以clone下来仓库就直接可以使用和阅读的。

准备protoc等工具

安装Protoc,目前 daprd 要求的版本是 v3.14.0。sdk 和 daprd保持一致。

具体见准备工作中的 安装Protoc

从proto文件生成Java代码

在 dapr java sdk 项目下,有名为 sdk-augogen的子项目,在这里执行 generate-sources 命令就可以生成对应的java类:

$ cd sdk-augogen
$ mvn generate-sources

代码生成的过程有几个主要步骤:

步骤1: 下载proto文件

从命令输出中能看到,maven会下载三个proto文件: common.proto, dapr.proto,appcallback.proto:

[INFO] --- download-maven-plugin:1.6.0:wget (getCommonProto) @ dapr-sdk-autogen ---
[INFO] Downloading: https://raw.githubusercontent.com/dapr/dapr/4a6369caaba9cf46eae9bfa4fa6e76b474854c89/dapr/proto/common/v1/common.proto
[INFO] Downloading: https://raw.githubusercontent.com/dapr/dapr/4a6369caaba9cf46eae9bfa4fa6e76b474854c89/dapr/proto/runtime/v1/dapr.proto
[INFO] Downloading: https://raw.githubusercontent.com/dapr/dapr/4a6369caaba9cf46eae9bfa4fa6e76b474854c89/dapr/proto/runtime/v1/appcallback.proto

对照 sdk-autogen 子项目下的 pom.xml 文件,可以找到相关的maven插件配置:

<plugin>
        <groupId>com.googlecode.maven-download-plugin</groupId>
        <artifactId>download-maven-plugin</artifactId>
        <version>1.6.0</version>
        <executions>
          <execution>
            <id>getCommonProto</id>
            <!-- the wget goal actually binds itself to this phase by default -->
            <phase>initialize</phase>
            <goals>
              <goal>wget</goal>
            </goals>
            <configuration>
              <url>${dapr.proto.baseurl}/common/v1/common.proto</url>
              <outputFileName>common.proto</outputFileName>
              <!-- default target location, just to demonstrate the parameter -->
              <outputDirectory>${protobuf.input.directory}/dapr/proto/common/v1</outputDirectory>
            </configuration>
          </execution>
          <execution>
            <id>getDaprProto</id>
            <!-- the wget goal actually binds itself to this phase by default -->
            <phase>initialize</phase>
            <goals>
              <goal>wget</goal>
            </goals>
            <configuration>
              <url>${dapr.proto.baseurl}/runtime/v1/dapr.proto</url>
              <outputFileName>dapr.proto</outputFileName>
              <!-- default target location, just to demonstrate the parameter -->
              <outputDirectory>${protobuf.input.directory}</outputDirectory>
            </configuration>
          </execution>
          <execution>
            <id>getDaprClientProto</id>
            <!-- the wget goal actually binds itself to this phase by default -->
            <phase>initialize</phase>
            <goals>
              <goal>wget</goal>
            </goals>
            <configuration>
              <url>${dapr.proto.baseurl}/runtime/v1/appcallback.proto</url>
              <outputFileName>appcallback.proto</outputFileName>
              <!-- default target location, just to demonstrate the parameter -->
              <outputDirectory>${protobuf.input.directory}</outputDirectory>
            </configuration>
          </execution>
        </executions>
      </plugin>

在这里特别要注意的是 ${dapr.proto.baseurl},这个属性在根目录下的 pom.xml 中设置,比如我当前版本的值是:

  <dapr.proto.baseurl>
https://raw.githubusercontent.com/dapr/
dapr/4a6369caaba9cf46eae9bfa4fa6e76b474854c89/dapr/proto
  </dapr.proto.baseurl>

这意味着如果要针对某个版本的 proto 文件进行代码生成,则需要修改这里的 ${dapr.proto.baseurl} 的值,比如指向某个分支/tag或者如上面指向某个commit。

步骤2: 生成代码

protoc-jar-maven-plugin 插件负责将前面下载的proto文件生成java 代码,生成之后的代码存在的 target/generated-sources 目录下:

[INFO] --- protoc-jar-maven-plugin:3.11.4:run (default) @ dapr-sdk-autogen ---
[INFO] Protoc version: 3.13.0
protoc-jar: protoc version: 3.13.0, detected platform: osx-x86_64 (mac os x/x86_64)
protoc-jar: cached: /var/folders/vr/8yl21p696dd41c776p67qlkm0000gp/T/protocjar.webcache/com/google/protobuf/protoc/maven-metadata.xml
protoc-jar: cached: /var/folders/vr/8yl21p696dd41c776p67qlkm0000gp/T/protocjar.webcache/com/google/protobuf/protoc/3.13.0/protoc-3.13.0-osx-x86_64.exe
protoc-jar: executing: [/var/folders/vr/8yl21p696dd41c776p67qlkm0000gp/T/protocjar852218627845177615/bin/protoc.exe, --version]
libprotoc 3.13.0

[INFO]     Processing (grpc-java): dapr.proto
[INFO]     Processing (grpc-java): common.proto
[INFO]     Processing (grpc-java): appcallback.proto

[INFO] Adding generated sources (java): /Users/sky/work/code/skyao/java-sdk/sdk-autogen/target/generated-sources
[INFO] Adding generated sources (grpc-java): /Users/sky/work/code/skyao/java-sdk/sdk-autogen/target/generated-sources

[INFO] BUILD SUCCESS

刷新项目,比如 idea 下可以在 java-sdk 根目录下pom.xml上右键 maven -> reload project 。

相关的文件路径小结

一目了然:

遇到过的问题

proto文件缓存

有一个比较坑的事情是,download-maven-plugin 插件在下载文件时,不是每次都去请求,有时会从maven本地缓存中拿文件。

比如我某次被坑的时候,就发现有如下日志:

[INFO] --- download-maven-plugin:1.6.0:wget 
[INFO] Got from cache: /Users/sky/.m2/repository/.cache/download-maven-plugin/common.proto_d701b2bbc1c789dfa25b99c95a8cd8c2
[INFO] Got from cache: /Users/sky/.m2/repository/.cache/download-maven-plugin/dapr.proto_372181342afa932d4684925872c96d22
[INFO] Got from cache: /Users/sky/.m2/repository/.cache/download-maven-plugin/appcallback.proto_e110e7ac8ee53213ecf133574e146d64
[INFO] 

这个缓存会导致拿到的 proto 文件和原来期望的proto文件内容可能不一样,因此后面生成的代码也会有偏差,某些情况下就会出现代码编译不过,错误可能是某个类或者某个方法找不到。

这个时候最简单的办法就是删除这个缓存目录,让 maven 去远程下载,然后再重新生成:

rm -rf ~/.m2/repository/.cache/download-maven-plugin/

mvn generate-sources

Error extracting protoc for version 3.17.3 错误

在配置 Artifactory 开启 mirror 之后,遇到一个奇怪的问题:

[ERROR] Failed to execute goal com.github.os72:protoc-jar-maven-plugin:3.11.4:run (default) on project dapr-sdk-autogen: Error extracting protoc for version 3.17.3: Unsupported platform: protoc-3.17.3-linux-x86_64.exe -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal com.github.os72:protoc-jar-maven-plugin:3.11.4:run (default) on project dapr-sdk-autogen: Error extracting protoc for version 3.17.3
    at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute (MojoExecutor.java:306)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:211)
......
Caused by: org.apache.maven.plugin.MojoExecutionException: Error extracting protoc for version 3.17.3
......
Caused by: java.io.FileNotFoundException: Unsupported platform: protoc-3.17.3-linux-x86_64.exe
......

修改 maven settings.xml ,不使用 artifactory 而是直接连接 maven 中央仓库,就可以回避这个问题。

参考: https://github.com/os72/protoc-jar-maven-plugin/issues/68