Java: maven assembly插件使用, maven打包jar, maven打包依赖包

主页:https://maven.apache.org/plugins/maven-assembly-plugin/usage.html

主页实例:

<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>3.1.0</version>
    <configuration>
        <archive>
            <manifest>
                <mainClass>com.ikeepstudying.justcode.Main</mainClass>
            </manifest>
        </archive>
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
    </configuration>
    <executions>
        <execution>
            <id>make-assembly</id> <!-- this is used for inheritance merges -->
            <phase>package</phase> <!-- bind to the packaging phase -->
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
</plugin>

打包命令:

mvn clean package

执行命令:

java -jar  ××××-with-dependencies.jar

当你使用 Maven 对项目打包时,你需要了解以下 3 个打包 plugin,它们分别是

plugin function
maven-jar-plugin maven 默认打包插件,用来创建 project jar
maven-shade-plugin 用来打可执行包,executable(fat) jar
maven-assembly-plugin 支持定制化打包方式,例如 apache 项目的打包方式

下面我们就简单介绍一下 maven-assembly-plugin。

首先,在pom.xml中<plugin></plugin>中添加assembly插件。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>x.x.x</version>
    <configuration>
        ...
    </configuration>
    <executions>
        <execution>
            ...
        </execution>
    </executions>
</plugin>

<execution></execution>中设置maven的某个生命周期与插件的那个目标相互绑定,常规配置如下:

<execution>
    <id>assembly</id>
    <phase>package</phase>
    <goals>
        <goal>single</goal>
    </goals>
</execution>

<configuration></configuration>中重要的配置有如下几项:

(1) 设置assembly的打包细节:

这个是assembly的关键配置,assembly给出了一种自带的打包方式,配置如下:

<configuration>
    <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
    </descriptorRefs>
    ...
</configuration>

这种方式打出的包是fat jar,也就是把依赖的jar包全部解压成class文件后,再与自己的代码打成一个jar包。

还有一种方式就是自定义打包,这种方式需要创建一个打包的配置文件:

<configuration>
    <descriptors>
        <descriptor>src/main/resources/assembly.xml</descriptor>
    </descriptors>
    ...
</configuration>

这个文件的路径及名称都可以自己指定的,lz这里命名为assembly.xml,格式如下:

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"           xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
    ...
</assembly>

第一个属性是<id></id>,但是lz不知道它的作用,随便起了个名字。

第二个属性是<formats></formats>,这个用来指定打包的类型,支持以下类型

      • “zip” – Creates a ZIP file format
      • “tar” – Creates a TAR format
      • “tar.gz” or “tgz” – Creates a gzip’d TAR format
      • “tar.bz2” or “tbz2” – Creates a bzip’d TAR format
      • “jar” – Creates a JAR format
      • “dir” – Creates an exploded directory format
      • “war” – Creates a WAR format

lz使用过zip、jar和dir(也就是输出到文件夹),都是好用的(貌似也支持同时定义多种格式,但是lz没尝试过),配置格式如下:

<formats>
    <format>jar</format>
</formats>

第三个属性是<includeBaseDirectory></includeBaseDirectory>,设置为true的话,会把指定打包的内容外在嵌套一个文件夹,没什么用处,所以lz都设置为false。

第四第五个属性都是来指定打包内容的,<fileSets></fileSets>用来设置所要打包的文件夹,<dependencySets></dependencySets>用来设置所要打包的依赖包。举个例子来说,lz想要把自己编写的代码编译后的class文件以及所需的依赖包的class文件打到jar包中,要如下设置:

<fileSets>
    <fileSet>
        <directory>${project.basedir}/target/classes/</directory>
        <outputDirectory>/</outputDirectory>
        <includes>
            <include>/**/*.class</include>
            <include>*.xml</include>
            <include>*.properties</include>
            <include>*.yaml</include>
        </includes>
    </fileSet>
</fileSets>
<dependencySets>
    <dependencySet>
        <outputDirectory>/</outputDirectory>
        <includes>
            <include>org.yaml:snakeyaml</include>
        </includes>
        <unpack>true</unpack>
    </dependencySet>
</dependencySets>

<directory></directory>指定所需打包内容所在文件夹,当然依赖就不用设置这个了。

<outputDirectory></outputDirectory>指定输出目录,lz在根目录输出,就设置为/。

<includes></includes>用来指定要打包的文件,不设置的话就全部都打包。还有一个与之对应的<excludes></excludes>,指定不被打入的文件。

<unpack></unpack>这个是依赖特有的,用来设置依赖包是否解压。true解压,就是以class的形式出现。false不解压,是以jar包的形式出现。但如果不解压的话,一般将依赖包放在执行包的外边,这样配置:

<formats>
    <format>dir</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
    <dependencySet>
        <outputDirectory>lib</outputDirectory>
        <excludes>
            <exclude>org.yaml:snakeyaml</exclude>
        </excludes>
    </dependencySet>
</dependencySets>

将format设置为dir,这样就将jar输出到可执行jar包的外面。lz指定在了dir文件夹下。

(2) 设置assembly打包的命名:

<appendAssemblyId></appendAssemblyId>来设置打出的包是否带有AssemblyId(也就是assembly.xml中设置的id)后缀。很好理解,但是这里有一点要特别注意:如果设置为false并且你要打出的包包括jar包的话,它会覆盖默认打出的包。这是因为在maven的打包阶段,还有一个插件也在执行,它就是maven-jar-plugin。它也会打出一个jar包,这个jar包就是你coding出的代码编译后的包。所以你要是想要那个包的话,要将这个值设置为true。

(3) 设置jar执行时的MANIFEST.MF:

MANIFEST.MF这个文件的作用就不多说了,在这里有两个配置是最主要的:mainclass和classpath,配置如下:

<archive>
    <manifest>
        <addClasspath>true</addClasspath>
        <classpathPrefix>lib/</classpathPrefix>
        <mainClass>com.pxene.dmp.main.JobManager</mainClass>
    </manifest>
</archive>

这里有一点要特别注意:因为assembly执行在package阶段,它所关联的依赖包的scope只是compile的,所以runtime阶段的jar包不会被指定在classpath下面(这个lz纠结了好久,才找到原因),所以lz把所有执行时期的依赖也设置为compile了。这种方式不太好,但是也没想到更好的解决方法。

描述符文件元素

id

<id>release</id>

id 标识符,添加到生成文件名称的后缀符。如果指定 id 的话,目标文件则是 ${artifactId}-${id}.tar.gz

formats

maven-assembly-plugin 支持的打包格式有zip、tar、tar.gz (or tgz)、tar.bz2 (or tbz2)、jar、dir、war,可以同时指定多个打包格式

  <formats>
    <format>tar.gz</format>
    <format>dir</format>
  </formats>

dependencySets

用来定制工程依赖 jar 包的打包方式,核心元素如下表所示。

元素 类型 作用
outputDirectory String 指定包依赖目录,该目录是相对于根目录
includes/include* List<String> 包含依赖
excludes/exclude* List<String> 排除依赖
<dependencySets>
    <dependencySet>
      <outputDirectory>/lib</outputDirectory>
    </dependencySet>
  </dependencySets>

fileSets

管理一组文件的存放位置,核心元素如下表所示。

元素 类型 作用
outputDirectory String 指定文件集合的输出目录,该目录是相对于根目录
includes/include* List<String> 包含文件
excludes/exclude* List<String> 排除文件
fileMode String 指定文件属性,使用八进制表达,分别为(User)(Group)(Other)所属属性,默认为 0644
<fileSets>
    <fileSet>
      <includes>
        <include>bin/**</include>
      </includes>
      <fileMode>0755</fileMode>
    </fileSet>

    <fileSet>
      <includes>
        <include>/conf/**</include>
        <include>logs</include>
      </includes>
    </fileSet>

  </fileSets>

files

可以指定目的文件名到指定目录,其他和 fileSets 相同,核心元素如下表所示。

元素 类型 作用
source String 源文件,相对路径或绝对路径
outputDirectory String 输出目录
destName String 目标文件名
fileMode String 设置文件 UNIX 属性
 <files>
    <file>
      <source>README.txt</source>
      <outputDirectory>/</outputDirectory>
    </file>
  </files>

样例

工程目录结构

Java: maven assembly插件使用, maven打包jar, maven打包依赖包
Java: maven assembly插件使用, maven打包jar, maven打包依赖包
scribe-log4j2-test

pom.xml

<build>
  <finalName>scribe-log4j2-test</finalName>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
    </plugin>

    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-assembly-plugin</artifactId>
      <configuration>
        <descriptors>
          <descriptor>src/main/assembly/release.xml</descriptor>
        </descriptors>
      </configuration>

      <executions>
        <execution>
          <id>make-assembly</id> <!-- this is used for inheritance merges -->
          <phase>package</phase> <!-- bind to the packaging phase -->
          <goals>
            <goal>single</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

release.xml

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">

  <formats>
    <format>tar.gz</format>
    <format>dir</format>
  </formats>

  <dependencySets>
    <dependencySet>
      <outputDirectory>/lib</outputDirectory>
    </dependencySet>
  </dependencySets>

  <fileSets>
    <fileSet>
      <includes>
        <include>bin/**</include>
      </includes>
      <fileMode>0755</fileMode>
    </fileSet>

    <fileSet>
      <includes>
        <include>/conf/**</include>
        <include>logs</include>
      </includes>
    </fileSet>

  </fileSets>

  <files>
    <file>
      <source>README.txt</source>
      <outputDirectory>/</outputDirectory>
    </file>
  </files>

</assembly>

最终创建生成可执行二进制工程

参考

maven 入门指南
maven 生命周期
Maven 默认插件以及功能
maven 依赖管理
maven-shade-plugin 入门指南
maven-assembly-plugin 

 

本文: Java: maven assembly插件使用, maven打包jar, maven打包依赖包