Maven - 打包之争:Jar vs. Shade vs. Assembly

文章目录


Pre

Maven - 统一构建规范:Maven 插件管理最佳实践


概述

Maven 提供了多种打包方式,其中常见的包括三种:jar、shade、assembly。下面是它们的详细比较:

  1. Jar 打包方式:

    • 描述: 这是最常见的打包方式,它创建一个标准的Java JAR文件。
    • 优点: 简单直接,适用于大多数简单项目。
    • 缺点: 不能包含项目的依赖,如果项目有外部依赖,用户必须手动将它们添加到类路径中。
  2. Shade 打包方式:

    • 描述: Maven Shade插件允许创建一个可执行的JAR文件,其中包含所有依赖。
    • 优点: 生成一个独立的可执行JAR,无需用户手动添加依赖。
    • 缺点: 可能会导致JAR文件较大,不适合所有项目。
  3. Assembly 打包方式:

    • 描述: Maven Assembly插件提供了一种更灵活的打包方式,允许创建各种自定义分发包。
    • 优点: 可以根据项目的需要创建定制的分发包,非常灵活。
    • 缺点: 配置相对复杂,适用于需要高度定制化的项目。

总结 :

  • Jar方式适用于简单项目,但对于有依赖的项目需要手动处理依赖 ; 默认的打包方式,用来打普通的project JAR包;。
  • Shade方式生成可执行JAR,但可能导致文件较大; 用来打可执行jar包,也就是所谓的fat JAR包。
  • Assembly方式最灵活,可以根据项目需求创建定制分发包 ; 自定义的打包结构,也可以定制依赖项等。

Jar 打包方式_maven-jar-plugin

Overview

使用maven-jar-plugin插件, 默认的打包方式,用来打普通的project JAR包 .


使用

java 复制代码
<build>
   <plugins>
       <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.1.0</version>
            <configuration>
                <archive>
                    <manifest>
                        <!-- 指定入口函数 -->
                        <mainClass>类的全路径名称</mainClass>
                        <!-- 是否添加依赖的jar路径配置 -->
                        <addClasspath>true</addClasspath>
                        <!-- 依赖的jar包存放位置,和生成的jar放在同一级目录下 -->
                        <classpathPrefix>lib/</classpathPrefix>
                    </manifest>
                </archive>
                <!-- 不打包com.artisan.excludes下面的所有类 -->
                <excludes>com/artisan/excludes/*</excludes>
            </configuration>
        </plugin>
    </plugins>
</build>

上面配置使用这个 jar包的时候就需要在它同一级的创建一个lib目录来存放。 可以使用includes或excludes选择的打包某些内容

官方文档

https://maven.apache.org/shared/maven-archiver/examples/classpath.html


Shade 打包方式_maven-shade-plugin

Overview

插件:使用maven-shade-plugin插件

maven-shade-plugin提供了两大基本功能:

  • 将依赖的jar包打包到当前jar包(常规打包是不会将所依赖jar包打进来的);
  • 对依赖的jar包进行重命名(用于类的隔离);

使用

maven-shade-plugin 只存在一个goal shade:shade,需要将其绑定到 phase package 上

java 复制代码
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-shade-plugin</artifactId>
      <version>3.1.1</version>
      <configuration>
        <!-- put your configurations here -->
      </configuration>
      <executions>
        <execution>
          <phase>package</phase>
          <goals>
            <goal>shade</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

然后在当前pom文件所在路径下,执行打包命令:mvn clean package


将部分jar包添加或排除

xml 复制代码
<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.1.1</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <artifactSet>
                <excludes>
                  <exclude>jmock:*</exclude>
                  <exclude>*:xml-apis</exclude>
                  <exclude>org.apache.maven:lib:tests</exclude>
                  <exclude>log4j:log4j:jar:</exclude>
                </excludes>
                <includes>
                    <include>junit:junit</include>
                </includes>
              </artifactSet>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>
  • jar包以groupId:artifactId[[:type]:classifier]的形式表示
  • 1.3版本后插件支持通配符 '*' and '?'

将依赖jar包内部资源添加或排除

xml 复制代码
<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.1.1</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <filters>
                <filter>
                  <artifact>junit:junit</artifact>
                  <includes>
                    <include>junit/framework/**</include>
                    <include>org/junit/**</include>
                  </includes>
                  <excludes>
                    <exclude>org/junit/experimental/**</exclude>
                    <exclude>org/junit/runners/**</exclude>
                  </excludes>
                </filter>
                <filter>
                  <artifact>*:*</artifact>
                  <excludes>
                    <exclude>META-INF/*.SF</exclude>
                    <exclude>META-INF/*.DSA</exclude>
                    <exclude>META-INF/*.RSA</exclude>
                  </excludes>
                </filter>
              </filters>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>

自动将所有不使用的类排除

xml 复制代码
<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.1.1</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <minimizeJar>true</minimizeJar>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>

将依赖的类重命名并打包进来 (隔离方案)

xml 复制代码
<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.1.1</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <relocations>
                <relocation>
                  <pattern>org.codehaus.plexus.util</pattern>
                  <shadedPattern>org.shaded.plexus.util</shadedPattern>
                  <excludes>
                    <exclude>org.codehaus.plexus.util.xml.Xpp3Dom</exclude>
                    <exclude>org.codehaus.plexus.util.xml.pull.*</exclude>
                  </excludes>
                </relocation>
              </relocations>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>

将"org.codehaus.plexus.util"重命名为"org.shaded.plexus.util",原始jar包中的"org.codehaus.plexus.util.xml.Xpp3Dom"和"org.codehaus.plexus.util.xml.pull"不会被重命名到目的包中;


修改包的后缀名

默认会生成一个Jar包和一个以 "-shaded"为结尾的uber-jar包,可以通过配置来指定uber-jar的后缀名。

xml 复制代码
<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.1.1</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <shadedArtifactAttached>true</shadedArtifactAttached>
              <shadedClassifierName>jackofall</shadedClassifierName> <!-- Any name that makes sense -->
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>

Invalid signature file digest for Manifest main attributes

原因:有些jar包生成时,会 使用jarsigner生成文件签名(完成性校验),分为两个文件存放在META-INF目录下:

java 复制代码
a signature file, with a .SF extension;
a signature block file, with a .DSA, .RSA, or .EC extension;

需要在生成 uber-jar时,将这些排除掉,不再进行完成性校验,如下所示:

xml 复制代码
<configuration>
 <filters>
    <filter>
      <artifact>*:*</artifact>
      <excludes>
        <exclude>META-INF/*.SF</exclude>
        <exclude>META-INF/*.DSA</exclude>
        <exclude>META-INF/*.RSA</exclude>
      </excludes>
    </filter>
  </filters>
</configuration>

https://maven.apache.org/plugins/maven-shade-plugin/examples/attached-artifact.html


官方文档

https://maven.apache.org/plugins/maven-shade-plugin/examples/attached-artifact.html


Assembly 打包方式_maven-assembly-plugin

Overview

使用maven-assembly-plugin插件 。

日常使用比较多的是maven-assembly-plugin插件

例如:大数据项目中往往有很多shell脚本、SQL脚本、.properties及.xml配置项等,采用assembly插件可以让输出的结构清晰而标准化


使用

首先在pom文件添加以下内容:

xml 复制代码
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>${maven-assembly-plugin.version}<version>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <!-- 绑定到package生命周期 -->
                    <phase>package</phase>
                    <goals>
                        <!-- 只运行一次 -->
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <!-- 配置描述符文件 -->
                <descriptor>src/main/assembly/assembly.xml</descriptor>
                <!-- 也可以使用Maven预配置的描述符
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs> -->
            </configuration>
        </plugin>
    </plugins>
</build>

然后编写描述符文件:

xml 复制代码
<assembly>
    <id>assembly</id>
    <formats>
        <format>tar.gz</format>
    </formats>
    <includeBaseDirectory>true</includeBaseDirectory>
    <fileSets>
        <fileSet>
            <directory>src/main/bin</directory>
            <includes>
                <include>*.sh</include>
            </includes>
            <outputDirectory>bin</outputDirectory>
            <fileMode>0755</fileMode>
        </fileSet>
        <fileSet>
            <directory>src/main/conf</directory>
            <outputDirectory>conf</outputDirectory>
        </fileSet>
        <fileSet>
            <directory>src/main/sql</directory>
            <includes>
                <include>*.sql</include>
            </includes>
            <outputDirectory>sql</outputDirectory>
        </fileSet>
        <fileSet>
            <directory>target/classes/</directory>
            <includes>
                <include>*.properties</include>
                <include>*.xml</include>
                <include>*.txt</include>
            </includes>
            <outputDirectory>conf</outputDirectory>
        </fileSet>
    </fileSets>
    <files>
        <file>
            <source>target/${project.artifactId}-${project.version}.jar</source>
            <outputDirectory>.</outputDirectory>
        </file>
    </files>
    <dependencySets>
        <dependencySet>
            <unpack>false</unpack>
            <scope>runtime</scope>
            <outputDirectory>lib</outputDirectory>
        </dependencySet>
    </dependencySets>
</assembly>
字段 解析
formats 是assembly插件支持的打包文件格式,有zip、tar、tar.gz、tar.bz2、jar、war。可以同时定义多个formats。
id 是添加到打包文件名的标识符,用来做后缀。比如说,如果按上面的配置,生成的文件就是artifactId-{artifactId}-artifactId-{version}-assembly.tar.gz
fileSets/fileSet 用来设置一组文件在打包时的属性。
directory 源目录的路径。
includes/excludes 设定包含或排除哪些文件,支持通配符。
fileMode 指定该目录下的文件属性,采用Unix八进制描述法,默认值是064。
outputDirectory 生成目录的路径。
files/file 与fileSets大致相同,不过是指定单个文件,并且还可以通过destName属性来设置与源文件不同的名称。
dependencySets/dependencySet 用来设置工程依赖文件在打包时的属性,也与fileSets大致相同。
dependencySet-unpack 布尔值,false表示将依赖以原来的JAR形式打包,true则表示将依赖解成*.class文件的目录结构打包。
dependencySet-scope 表示符合哪个作用范围的依赖会被打包进去。compile与provided都不用管,一般是写runtime。

按照以上配置打包好后,将.tar.gz文件上传到服务器,解压之后就会得到bin、conf、lib等规范化的目录结构,十分方便。


官方文档

https://maven.apache.org/plugins/maven-assembly-plugin/examples/single/filtering-some-distribution-files.html

相关推荐
super_lzb1 天前
springboot打war包时将外部配置文件打入到war包内
java·spring boot·后端·maven
小毛驴8501 天前
Maven同时配置阿里云仓库和私有仓库
java·阿里云·maven
susu10830189111 天前
docker部署 Java 项目jar
java·docker·jar
KawYang1 天前
Spring Boot 使用 PropertiesLauncher + loader.path 实现外部 Jar 扩展启动
spring boot·后端·jar
howeres1 天前
基于 Spring Boot 的插件化 JAR 包热加载方案
spring boot·jar
多米Domi0111 天前
0x3f 第23天 黑马web (前端三件套,maven,web入门、mysql)黑马反射注解 hot100普通数组
java·python·mysql·算法·leetcode·maven
zhanjixun2 天前
Spring Boot Maven项目构建Docker镜像
spring boot·docker·maven
2501_941882482 天前
高可用数据库设计与分片策略在大规模系统中的实践分享
spring·maven
青衫码上行2 天前
Maven介绍和下载与安装
java·maven
计算机毕设指导62 天前
基于微信小程序的烧烤店点餐和结账系统【源码文末联系】
java·spring·微信小程序·小程序·tomcat·maven·intellij-idea