maven 各种打包姿势, 再也不用担心各种花样打包了
在工作当中, 由于各种框架需要, 环境需要, 平台需要, 要求我们使用 maven 打包出各种类型的 jar 文件, 通过下述案例, 可针对当前应用场景使用不同方式的打包技术
需要给 jar 包加 git 版本号
在 pom 文件里可以使用下面的任意属性, 比如给 finalName 标签增加 git 版本号
1
<finalName>${artifactId}-${version}-${git.commit.id.abbrev}</finalName>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
  "git.branch": "master",
  "git.build.host": "localhost",
  "git.build.time": "2019-08-28 17:05:33",
  "git.build.user.email": "xxx@163.com",
  "git.build.user.name": "xxx",
  "git.build.version": "1.1.1",
  "git.closest.tag.commit.count": "",
  "git.closest.tag.name": "",
  "git.commit.id": "437e26172c51cab8fc88ea585145797df222fbb2",
  "git.commit.id.abbrev": "437e261",
  "git.commit.id.describe": "437e261-dirty",
  "git.commit.id.describe-short": "437e261-dirty",
  "git.commit.message.full": "获取版本信息",
  "git.commit.message.short": "获取版本信息",
  "git.commit.time": "2019-08-27 19:07:03",
  "git.commit.user.email": "xxx@163.com",
  "git.commit.user.name": "xxx",
  "git.dirty": "true",
  "git.remote.origin.url": "http://git.xxx.cn/gitlab/git/xxx.git",
  "git.tags": "",
  "git.total.commit.count": "3324"
}
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
<plugin>
  <groupId>pl.project13.maven</groupId>
  <artifactId>git-commit-id-plugin</artifactId>
  <version>2.2.5</version>
  <executions>
    <execution>
      <id>get-the-git-infos</id>
      <phase>
        prepare-package
      </phase>
      <goals>
        <goal>revision</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
    <prefix>git</prefix>
    <verbose>false</verbose>
    <dateFormat>yyyy-MM-dd HH:mm:ss</dateFormat>
    <generateGitPropertiesFile>true</generateGitPropertiesFile>
    <generateGitPropertiesFilename>${project.build.outputDirectory}/git.properties</generateGitPropertiesFilename>
    <format>json</format>
    <abbrevLength>7</abbrevLength>
    <gitDescribe>
      <skip>false</skip>
      <always>false</always>
      <dirty>-dirty</dirty>
    </gitDescribe>
  </configuration>
</plugin>
场景 1: docker 容器需要的 jar
首先保证 docker 在宿主机上的环境是一样的, 其次, 在宿主机上建设统一路径的文件夹, 如: /usr/share/gomyck/xxx
使用下述插件打包, 可把当前工程打成分散的小包:
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>appassembler-maven-plugin</artifactId>
  <version>2.1.0</version>
  <executions>
    <execution>
      <goals>
        <goal>assemble</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <repositoryLayout>flat</repositoryLayout>
    <!-- 打包的jar,以及maven依赖的jar放到这个目录里面 -->
    <repositoryName>lib</repositoryName>
    <useWildcardClassPath>true</useWildcardClassPath>
    <!-- 配置文件的目标目录 -->
    <configurationDirectory>conf</configurationDirectory>
    <!-- 拷贝配置文件到上面的目录中 -->
    <copyConfigurationDirectory>true</copyConfigurationDirectory>
    <!-- 从哪里拷贝配置文件 (默认src/main/config) -->
    <configurationSourceDirectory>src/main/resources</configurationSourceDirectory>
    <includeConfigurationDirectoryInClasspath>true</includeConfigurationDirectoryInClasspath>
    <!--生成的项目的目录位置,这里的client是项目的名称,你可以根据你的需要自己随便命名 -->
    <assembleDirectory>${project.build.directory}/dist</assembleDirectory>
    <!-- 可执行脚本的目录 -->
    <binFolder>bin</binFolder>
    <programs>
      <program>
        <id>main</id>
        <!-- 启动类地址 -->
        <mainClass>cn.net.hylink.qingzhi.MessageRouteApplication</mainClass>
        <!-- 生成的脚本文件的名称,比如start.sh,你也可以根据你的需要命名成其他名字 -->
        <name>start</name>
        <jvmSettings>
          <initialMemorySize>20m</initialMemorySize>
          <maxMemorySize>256m</maxMemorySize>
          <maxStackSize>128m</maxStackSize>
          <systemProperties>
            <systemProperty>xxx=23456</systemProperty>
            <systemProperty>vvv="xaz"</systemProperty>
          </systemProperties>
          <extraArguments>
            <!-- <extraArgument>-server</extraArgument> -->
            <!-- <extraArgument>-Xmx1G</extraArgument> -->
            <!-- <extraArgument>-Xms1G</extraArgument> -->
          </extraArguments>
        </jvmSettings>
      </program>
    </programs>
    <!-- 生成linux, windows两种平台的执行脚本 -->
    <platforms>
      <platform>windows</platform>
      <platform>unix</platform>
    </platforms>
    <binFileExtensions>
      <unix>.sh</unix>  <!-- 设置生成文件为xshell脚本格式 -->
    </binFileExtensions>
  </configuration>
</plugin>
生成的目录结构:
1
2
3
4
5
--dist
  --bin   可执行脚本存放文件夹
  --conf  配置文件文件夹
  --lib   jar 包(所有的依赖和当前工程, 均打成小 jar)
使用该方式打包的 jar, 通过与jre 镜像的约定规则, 自动调用 start.sh完成服务的启动, 以后每次升级, 只需要替换 lib 中的工程 jar 就可以, 不需要替换额外的依赖 jar, 每次升级只需要传几百KB的文件即可
场景 2: flink 需要的 jar
通过 flink 启动的 task 需要的 jar 为完整的 fatjar, 通常情况下, 我们可以使用 flink 官方例子中的 shade 插件来完成打包
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<!-- We use the maven-shade plugin to create a fat jar that contains all necessary dependencies. -->
<!-- Change the value of <mainClass>...</mainClass> if your program entry point changes. -->
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <version>3.0.0</version>
  <executions>
    <!-- Run shade goal on package phase -->
    <execution>
      <phase>package</phase>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <artifactSet>
          <excludes>
            <exclude>org.apache.flink:flink-shaded-force-shading</exclude>
            <exclude>org.apache.flink:flink-streaming-java</exclude>
            <exclude>org.apache.flink:flink-clients</exclude>
            <exclude>com.google.code.findbugs:jsr305</exclude>
            <!--<exclude>org.slf4j:*</exclude>-->
            <exclude>org.apache.logging.log4j:*</exclude>
          </excludes>
        </artifactSet>
        <filters>
          <filter>
            <!-- Do not copy the signatures in the META-INF folder.
            Otherwise, this might cause SecurityExceptions when using the JAR. -->
            <artifact>*:*</artifact>
            <excludes>
              <exclude>META-INF/*.SF</exclude>
              <exclude>META-INF/*.DSA</exclude>
              <exclude>META-INF/*.RSA</exclude>
            </excludes>
          </filter>
        </filters>
        <transformers>
          <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <mainClass>com.gomyck.FlinkItApplication</mainClass>
          </transformer>
          <!-- 这个配置会使 META-INF/services 文件夹下的文件合并, 因为使用了 spi 的机制, 会存在好多 services的文件, 涉及到相同接口的实现会覆盖 -->
          <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
          <!-- 下面的配置是为了把 spring 的元数据配置合并, 否则这些文件会覆盖 -->
          <!--
          <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
            <resource>META-INF/spring.handlers</resource>
          </transformer>
          <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
            <resource>META-INF/spring.schemas</resource>
          </transformer>
          <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
            <resource>META-INF/spring.tooling</resource>
          </transformer>
          <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
            <resource>META-INF/spring.factories</resource>
          </transformer>
          -->
        </transformers>
      </configuration>
    </execution>
  </executions>
</plugin>
这种方式打的 jar 包是 fatjar, 并且会排除 flink runtime 中存在的依赖, 并且这种依赖排除是传递的: 比如排除的是 org.apache.flink:flink-clients, 那么这个依赖 pom 文件中的所有依赖将会被排除
相反的例子就是使用 maven-dependence 插件排除依赖, org.apache.flink:flink-clients 仅仅会排除自身, 但这个依赖 pom 文件中描述的其他依赖, 将会被打进 fatjar 中
上述例子可以打包出 fatjar, 但不支持在工程中使用 spring 容器, 读取不到配置文件, 没找到原因, 而且这种打包方式会把所有的依赖转换成 class, 与工程文件混在一起, 不好维护
最后使用下述的方式解决 fatjar 打包问题
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-dependency-plugin</artifactId>
  <executions>
    <execution>
      <id>copy-compile-dependencies</id>
      <phase>package</phase>
      <goals>
        <goal>copy-dependencies</goal>
      </goals>
      <configuration>
        <type>jar</type>
        <includeTypes>jar</includeTypes>
        <outputDirectory>
          ${project.build.directory}/lib
        </outputDirectory>
        <excludeScope>provided</excludeScope>
        <!-- 依赖传递, 打开这个也有问题, 不用这个注解, 仅排除依赖自身 -->
        <!--<excludeTransitive>true</excludeTransitive>-->
      </configuration>
    </execution>
  </executions>
</plugin>
  <!-- 这个插件没啥用, 主要是打单体 jar 时, 用一用 -->
  <!--<plugin>-->
  <!--  <groupId>org.apache.maven.plugins</groupId>-->
  <!--  <artifactId>maven-jar-plugin</artifactId>-->
  <!--  <configuration>-->
  <!--    <classesDirectory>target/classes/</classesDirectory>-->
  <!--    <archive>-->
  <!--      <!–生成的jar中,不要包含pom.xml和pom.properties这两个文件–>-->
  <!--      <addMavenDescriptor>false</addMavenDescriptor>-->
  <!--      <manifest>-->
  <!--        <mainClass>com.gomyck.FlinkItApplication</mainClass>-->
  <!--        <!– 打包时 MANIFEST.MF文件不记录的时间戳版本 –>-->
  <!--        <useUniqueVersions>false</useUniqueVersions>-->
  <!--        <addClasspath>true</addClasspath>-->
  <!--        <classpathPrefix>lib/</classpathPrefix>-->
  <!--      </manifest>-->
  <!--      <manifestEntries>-->
  <!--        <!–jar中的MANIFEST.MF文件ClassPath需要添加config目录才能读取到配置文件–>-->
  <!--        <Class-Path>config/ .</Class-Path>-->
  <!--      </manifestEntries>-->
  <!--    </archive>-->
  <!--  </configuration>-->
  <!--</plugin>-->
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.3</version>
<executions>
  <execution>
    <id>copy-lib-src-webapps</id>
    <phase>install</phase>
    <goals>
      <goal>run</goal>
    </goals>
    <configuration>
      <tasks>
        <echo message="开始构建JAR包..."/>
        <copydir dest="${project.build.directory}/${project.build.finalName}-final/lib"
                 src="${project.build.directory}/lib/"/>
        <copydir dest="${project.build.directory}/${project.build.finalName}-final/"
                 src="${project.build.directory}/classes/"/>
        <jar basedir="${project.build.directory}/${project.build.finalName}-final/"
             destfile="${project.build.directory}/${project.build.finalName}-final.jar">
          <manifest>
            <attribute name="Main-Class" value="com.gomyck.FlinkItApplication"/>
          </manifest>
        </jar>
      </tasks>
    </configuration>
  </execution>
</executions>
</plugin>
其他 fatjar 打包方式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<plugin>
  <artifactId>maven-assembly-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <!--这里要替换成jar包main方法所在类 -->
        <mainClass>com.gomyck.mail.MailSend</mainClass>
      </manifest>
    </archive>
    <descriptorRefs>
      <descriptorRef>jar-with-dependencies</descriptorRef>
    </descriptorRefs>
  </configuration>
  <executions>
    <execution>
      <id>make-assembly</id>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
    </execution>
  </executions>
</plugin>
groovy 打包方式
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
38
39
40
41
42
43
44
<dependency>
  <groupId>org.codehaus.groovy</groupId>
  <artifactId>groovy-all</artifactId>
  <version>3.0.17</version>
  <type>pom</type>
</dependency>
<plugin>
  <groupId>org.codehaus.gmavenplus</groupId>
  <artifactId>gmavenplus-plugin</artifactId>
  <version>1.7.1</version>
  <executions>
    <execution>
      <goals>
        <goal>addSources</goal>
        <goal>addTestSources</goal>
        <goal>generateStubs</goal>
        <goal>compile</goal>
        <goal>generateTestStubs</goal>
        <goal>compileTests</goal>
        <goal>removeStubs</goal>
        <goal>removeTestStubs</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <sources>
      <!-- 在此节点下配置源码目录,可配置多个 -->
      <source>
        <directory>${project.basedir}/src/main/groovy</directory>
        <includes>
          <include>**/*.groovy</include>
        </includes>
      </source>
      <source>
        <directory>${project.basedir}/src/additionalGroovy</directory>
        <includes>
          <include>**/*.groovy</include>
        </includes>
      </source>
    </sources>
  </configuration>
</plugin>