通过maven自动化构建protobuf class代码

通过maven自动化构建protocal buffer

当对代码进行工程构建的时候,如果能够尽可能的自动化,这样对于提升整个软件质量、节省人力成本、减少因为人工干预导致的各种不可预知的错误是很好。
从protobuf的官方文档来看,通过cmd调用protoc当然可以生成相应的代码,但是对构建不够友好。于是,可以考虑通过maven来进行自动化构建,在启动maven构建的时候,自动调用protoc,生成代码,并打包成相应的jar包,集成到工程发布包中。
这里有2种方式,如下。

第1种方式:使用protobuf-maven-plugin

配置插件protobuf-maven-plugin

先从官网[2]上将protobuf的工具包下载下来,然后拷贝到工程目录下,配置POM文件如下, 通过相对路径引用protoc.exe文件。
.protow文件默认的路径在src/main/proto文件中。下面所有的子目录都会被当成包结构。

protobuf-maven-plugin[1]的maven配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<configuration>
<checkStaleness>false</checkStaleness>
<staleMillis>10000</staleMillis>
<protocExecutable>${basedir}\..\protobuf\bin\protoc.exe</protocExecutable>
<useArgumentFile>true</useArgumentFile>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

进一步改进maven配置

如果我们的POM构建需要同时支持不同的平台,比如windows,MAC,Linux,但是这些平台上的protoc路径和文件都不一样,怎么办呢? 可以考虑如下方式。

通过profiles[3]<activation>如果通过profiles来激活不同的脚本调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<profiles>
<profile>
<id>windows</id>
<activation>
<os>
<family>Windows</family>
<arch>x86</arch>
</os>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<configuration>
<checkStaleness>false</checkStaleness>
<staleMillis>10000</staleMillis>
<protocExecutable>${basedir}\..\protobuf\bin\protoc.exe</protocExecutable>
<useArgumentFile>true</useArgumentFile>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>

第2种方式通过antrun插件来完成

通过组合os-maven-plugin, maven-antrun-plugin,build-helper-maven-plugin等多个插件来完成,效果是完全一样的。
这个例子[4]的价值在于maven的灵活性和可定制型,对于理解如何使用maven来达到比较复杂的目的很有帮助。特别是antrun插件,很多遗留的工程在满足条件的情况下可以往maven进行迁移。
参考文档:

前置条件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<properties>

<!-- protobuf paths -->
<protobuf.input.directory>${project.basedir}/src/main/proto</protobuf.input.directory>
<protobuf.output.directory>${project.build.directory}/generated-sources</protobuf.output.directory>

<!-- library versions -->
<build-helper-maven-plugin.version>1.9.1</build-helper-maven-plugin.version>
<maven-antrun-plugin.version>1.8</maven-antrun-plugin.version>
<maven-dependency-plugin.version>2.10</maven-dependency-plugin.version>
<maven-shade-plugin.version>2.4.2</maven-shade-plugin.version>
<os-maven-plugin.version>1.4.1.Final</os-maven-plugin.version>
<protobuf.version>3.0.0-beta-1</protobuf.version>

</properties>

配置依赖的Protocol Buffer API

1
2
3
4
5
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>${protobuf.version}</version>
</dependency>

检查操作系统类型,并生成相应的工程属性Properties

1
2
3
4
5
6
7
8
9
10
11
12
<build>
<extensions>
<!-- provides os.detected.classifier (i.e. linux-x86_64, osx-x86_64) property -->
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>${os-maven-plugin.version}</version>
</extension>
</extensions>

<!-- ... -->
</build>

自动下载平台相关的编译器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!-- copy protoc binary into build directory -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>${maven-dependency-plugin.version}</version>
<executions>
<execution>
<id>copy-protoc</id>
<phase>generate-sources</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>com.google.protobuf</groupId>
<artifactId>protoc</artifactId>
<version>${protobuf.version}</version>
<classifier>${os.detected.classifier}</classifier>
<type>exe</type>
<overWrite>true</overWrite>
<outputDirectory>${project.build.directory}</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>

调用protoc生成相关的Java代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!-- compile proto buffer files using copied protoc binary -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>${maven-antrun-plugin.version}</version>
<executions>
<execution>
<id>exec-protoc</id>
<phase>generate-sources</phase>
<configuration>
<target>
<property name="protoc.filename" value="protoc-${protobuf.version}-${os.detected.classifier}.exe"/>
<property name="protoc.filepath" value="${project.build.directory}/${protoc.filename}"/>
<chmod file="${protoc.filepath}" perm="ugo+rx"/>
<mkdir dir="${protobuf.output.directory}" />
<path id="protobuf.input.filepaths.path">
<fileset dir="${protobuf.input.directory}">
<include name="**/*.proto"/>
</fileset>
</path>
<pathconvert pathsep=" " property="protobuf.input.filepaths" refid="protobuf.input.filepaths.path"/>
<exec executable="${protoc.filepath}" failonerror="true">
<arg value="-I"/>
<arg value="${protobuf.input.directory}"/>
<arg value="--java_out"/>
<arg value="${protobuf.output.directory}"/>
<arg line="${protobuf.input.filepaths}"/>
</exec>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>

将Java代码添加到包中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!-- add generated proto buffer classes into the package -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>${build-helper-maven-plugin.version}</version>
<executions>
<execution>
<id>add-classes</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${protobuf.output.directory}</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>

对Protocol Buffer包进行shading

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!--  shade protobuf to avoid version conflicts -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>${maven-shade-plugin.version}</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<relocation>
<pattern>com.google.protobuf</pattern>
<shadedPattern>${project.groupId}.${project.artifactId}.shaded.protobuf</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>

  1. 1.插件使用:https://www.xolstice.org/protobuf-maven-plugin/plugin-info.html
  2. 2.下载protoc: https://developers.google.com/protocol-buffers/docs/downloads
  3. 3.maven profiles: http://maven.apache.org/guides/introduction/introduction-to-profiles.html
  4. 4.maven-protobuf-compile: https://vlkan.com/blog/post/2015/11/27/maven-protobuf/