gRPC-SpringBoot 共享.proto文件包问题

共享包引入后如何使用

引入共享包依赖

在pom文件的dependencies里引入依赖,注意需要声明 classifierproto 值,如下所示

xml 复制代码
<dependencies>
 <dependency>
     <groupId>com.fotile.grpc</groupId>
     <artifactId>fotile-grpc-client</artifactId>
     <classifier>proto</classifier>
     <scope>provided</scope>
 </dependency>
</dependencies>

这里是为了工程能先正常引用包,所以必须要先设置

解压

在build里 使用maven插件:maven-dependency-plugin 这个插件的目的主要是将你依赖进来的jar包进行解压,并可以指定输出到特定的目录

xml 复制代码
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <!--  一个id,用于区分不同的execution -->
            <id>unpack-proto-shared</id>
            <!-- 指定在哪个 maven phase 执行,这里必须指定在initialize阶段,放在编译源码(generate-sources)阶段之前 -->
            <phase>initialize</phase>
            <goals>
                <!-- 指定插件的执行目标: 解压缩包 -->
                <goal>unpack</goal>
            </goals>
            <configuration>
              <!-- 指定需要处理的包 -->
                <artifactItems>
                    <!--                             you can add more    -->
                    <artifactItem>
                        <groupId>com.fotile.grpc</groupId>
                        <artifactId>fotile-grpc-client</artifactId>
                        <version>${client-version}</version>
                        <classifier>proto</classifier>
                         <!-- project.build.directory 默认就是我们平常打包的target目录   -->
                        <outputDirectory>${project.build.directory}/proto-shared</outputDirectory>
                    </artifactItem>
                </artifactItems>
            </configuration>
        </execution>
    </executions>
</plugin>

这里指定的输出目录 outputDirectory 的值 : 需要和后面gRPC编译处理.proto文件的源文件路径要对应。

生成源码

使用的插件是 protobuf-maven-plugin, github 上的源码工程:github.com/xolstice/pr... 因为gRPC的运行会根据不同平台(mac,linux,win等)选择,所以需要指定proto相关的artifact

xml 复制代码
<configuration>
    <protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}
    </protocArtifact>
    <pluginId>grpc-java</pluginId>
    <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}
    </pluginArtifact>
    <protoSourceRoot>${basedir}/src/main/proto</protoSourceRoot>
    <!-- 输出目录 -->
    <outputDirectory>${project.build.directory}/generated-sources/protobuf/java</outputDirectory>
    <!--  need set false, for clean by next compile extension                  -->
    <clearOutputDirectory>false</clearOutputDirectory>

</configuration>

这里的protoSourceRoot 一般不需要指定,默认为:/src/main/proto 所以我们写代码时最好也是放在这个目录下。 outputDirectory 是指将生成的java源码文件放在哪个目录,默认情况下都是放在 ${project.build.directory}/generated-sources/protobuf/java 也就是: target/generated-sources/protobuf/java 下。 需要注意这里有个属性 clearOutputDirectory 默认值是true,也就是多次执行的话每次都会删除上一次生成的代码,对于我们有多个 execution 和多goal 的情况,必须设置为false,否则前面的生成的代码就会被删除掉,只剩下最后一个execution执行的最后一个goal后的结果

再来说明executions 部分。这里定义了2个,将内部和外部的分开定义执行,主要原因是因为protoSourceRoot属性只能指定一个目录,对于外部和自己内部都有.proto文件的情况下,无法解决。 这里可以看到 通过protoSourceRoot的值指定,可以与上面的 maven-dependency-plugin 插件 outputDirectory 值结合起来,用于生成源码。

xml 复制代码
<executions>


    <!-- step1: compile import .proto files -->
    <execution>
        <id>compile-out-proto</id>
        <phase>generate-sources</phase>
        <goals>
            <goal>compile</goal> <!-- generate client source codes -->
            <goal>compile-custom</goal> <!-- generate gRPC codes for gRPC-server -->
        </goals>
        <configuration>
            <protoSourceRoot>${project.build.directory}/proto-shared</protoSourceRoot>
            <outputDirectory>${project.build.directory}/generated-sources/protobuf/java</outputDirectory>
        </configuration>
    </execution>

    <!-- step2: compile self .proto files -->
    <execution>
        <phase>generate-sources</phase>
        <goals>
            <goal>compile</goal> <!-- generate client source codes -->
            <goal>compile-custom</goal> <!-- generate gRPC codes for gRPC-server -->
        </goals>
        <configuration>
            <outputDirectory>${project.build.directory}/generated-sources/protobuf/java</outputDirectory>
        </configuration>
    </execution>
</executions>

上面还有一个需要注意的点:

xml 复制代码
<goals>
    <goal>compile</goal> <!-- generate client source codes -->
    <goal>compile-custom</goal> <!-- generate gRPC codes for gRPC-server -->
</goals>

这里指定了2个 goal 第一个 compile 是生成client相关代码的,包括 外部需要使用gRPC client时引用的*Stud 和入参出参。第二个 compile-custom 是用于生成给gRPC Server使用的对象用的,*Grpc*ImplBase这里的java文件。所以需要注意下,在server里,这2个goal都是需要标注的,在gRPC invoker(调用方),仅需要 compile 一个goal就行。

源码加入源文件目录

使用 build-helper-maven-plugin 插件将上面插件生成的java源码目录,加入到工程源码里,方便IDE识别。

xml 复制代码
<!-- add codes from proto  to the build path  -->
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>build-helper-maven-plugin</artifactId>
    <executions>
        <execution>
            <id>add-source</id>
            <phase>generate-sources</phase> <!-- which maven parse execute -->
            <goals>
                <goal>add-source</goal>
            </goals>
            <configuration>
                <sources>
                    <source>${project.build.directory}/generated-sources/protobuf/java</source>
                </sources>
            </configuration>
        </execution>
    </executions>
</plugin>

总结

插件 maven-dependency-plugin 的 属性值

xml 复制代码
<executions>
  <execution>
    <configuration>
       <artifactItems>
          <artifactItem>
            <outputDirectory>${project.build.directory}/proto-shared</outputDirectory>
          </artifactItem>
       </artifactItems>
    </configuration>
  </execution>
</executions>

需要和 protobuf-maven-plugin 插件里的 <protoSourceRoot> 值保持一致

bash 复制代码
<execution>
   <configuration>
       <protoSourceRoot>${project.build.directory}/proto-shared</protoSourceRoot>
       <outputDirectory>${project.build.directory}/generated-sources/protobuf/java</outputDirectory>
   </configuration>
</execution>

同时 protobuf-maven-plugin 插件里的 <outputDirectory> 值要与 build-helper-maven-plugin 插件里的值 <source> 一直

xml 复制代码
<executions>
   <execution>
       <configuration>
           <sources>
               <source>${project.build.directory}/generated-sources/protobuf/java</source>
           </sources>
       </configuration>
   </execution>
</executions>

讲讲一些曲折

一开始使用protobuf-maven-plugin 插件时,是没有区分 execution 的,而是通过 <additionalProtoPathElements>标签来解决,因为很多地方都是这么建议,但是实际上是有问题无法生效的。下面是一个类似的配置

xml 复制代码
<configuration>
    <protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}
    </protocArtifact>
    <pluginId>grpc-java</pluginId>
    <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}
    </pluginArtifact>
    <protoSourceRoot>${basedir}/src/main/proto</protoSourceRoot>
    <!-- 输出目录 -->
    <outputDirectory>${project.build.directory}/generated-sources/protobuf/java</outputDirectory>
    <!--  need set false, for clean by next compile extension                  -->
    <clearOutputDirectory>true</clearOutputDirectory>
    <additionalProtoPathElements>
        <additionalProtoPathElement>
            ${basedir}/src/main/proto
        </additionalProtoPathElement>
        <additionalProtoPathElement>
            ${project.build.directory}/proto-shared
        </additionalProtoPathElement>
    </additionalProtoPathElements>

</configuration>

那具体原因我们就单独开一篇文章讲解

完整源码

github.com/Fotile/foti...

相关推荐
ai小鬼头1 小时前
创业小公司如何低预算打造网站?熊哥的实用建站指南
前端·后端
Andrew_Ryan2 小时前
Chisel 工具使用教程
后端
AntBlack2 小时前
体验了一把 paddleocr , 顺便撸了一个 桌面端 PDF识别工具
后端·python·计算机视觉
用户1512905452202 小时前
C 语言教程
前端·后端
UestcXiye2 小时前
Rust Web 全栈开发(十):编写服务器端 Web 应用
前端·后端·mysql·rust·actix
用户1512905452202 小时前
基于YOLOv10算法的交通信号灯检测与识别
后端
用户1512905452202 小时前
Netstat命令详解(windows下)
后端
用户1512905452202 小时前
GetTickCount() 函数的作用和用法
后端
能活着就行2 小时前
Java线程的三种创建方式
后端
努力的小郑3 小时前
Spring Boot整合阿里云OSS企业级实践:高可用文件存储解决方案
spring boot·后端·阿里云