共享包引入后如何使用
引入共享包依赖
在pom文件的dependencies
里引入依赖,注意需要声明 classifier
为 proto
值,如下所示
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>
那具体原因我们就单独开一篇文章讲解