【Maven】Maven打包机制详解

Maven打包的类型?

以下是几种常见的打包形式:

1、jar (Java Archive)

  • 用途:用于包含 Java 类文件其他资源(如属性文件、配置文件等)的库项目。
  • 特点
    • 可以被其他项目作为依赖引用。
    • 适合创建独立的应用程序或可重用的组件。
  • 生成文件.jar文件。

2、war (Web Application Archive)

  • 用途:专为 Web 应用程序设计,包含了 Servlets、JSP 页面、静态资源(如 HTML、CSS、JavaScript)、以及其他必要的配置文件。
  • 特点
    • 部署在应用服务器上,如 Apache Tomcat、JBoss 等。
    • 包含一个特殊的目录结构,例如WEB-INF/classesWEB-INF/lib
  • 生成文件.war文件。

3、pom (Project Object Model)

  • 用途:不是实际的二进制打包格式,而是用来表示一个多模块项目的父 POM。
  • 特点
    • 不会产生任何输出文件,除非指定了具体的构建目标。
    • 定义了一组共享的配置信息给子模块使用。
    • 有助于管理大型、复杂的企业级项目。
  • 生成文件:无直接生成的文件,但会生成元数据(如.pom文件),用于描述项目及其依赖关系。

4、 maven-plugin

  • 用途:在自定义插件时,需要指定打包类型为 maven-plugin。最后生成的是 jar 包。

为了指定打包类型,需要在项目的pom.xml文件中定义<packaging>元素。例如:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    ...
    <packaging>jar</packaging>
    ...
</project>

附:

1、与 packaging 标签相对的标签是 type,表示引入依赖的类型,例如 pom 类型、jar 类型,默认为 jar 类型。

2、jar 和 war 的比较:
在这里插入图片描述

3、Maven 打包文件的来源?[14]

虽然 src/main 是放置源代码和资源的地方,但实际打包的是经过编译和处理后存放在 target 目录下的文件target 目录是构建工具用来存放所有中间产物和最终产物的地方,在每次构建时可能会被清理或更新。

Maven打的jar包有各种依赖吗?

Maven 构建的 JAR 文件是否包含依赖项取决于如何配置构建过程。Maven 提供了几种不同的方式来打包项目,每种方式对依赖项的处理不同:

1、普通 JAR

这是默认的打包方式,当运行 mvn clean package 命令时,Maven 会编译代码并将其打包成一个 JAR 文件,但不会将项目的依赖项包含在这个 JAR 文件中。这意味着生成的 JAR 文件只包含您的项目代码和资源文件。

使用场景:运行环境已经提供了所需依赖,如 big-marketing 项目就使用 Docker 提供了 MySQL、Redis 等。

2、带有依赖的 JAR(Fat/Uber JAR)

有时候可能想要创建一个包含所有依赖项的 JAR 文件,这样就可以直接运行而不需要额外的类路径设置。为了实现这一点,可以使用 Maven 的插件,例如 maven-shade-pluginmaven-assembly-plugin

(1) 使用 maven-shade-plugin 创建 Fat JAR:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.2.4</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

(2) 使用 maven-assembly-plugin 创建 Fat JAR:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>3.3.0</version>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
                <archive>
                    <manifest>
                        <mainClass>com.example.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

使用场景:当需要一个独立的、可执行的 JAR 文件时。更确切地说,是自定义的归档文件。

Maven打包的插件有几个?

  • maven-jar-plugin:jar:将普通项目或模块打成 jar 包
  • maven-war-plugin:war:将 JaveWeb 项目或模块打成 war 包
  • maven-shade-plugin:shade在 jar 目标打包的基础上,将 compile 和 runtime 的依赖打进 fat jar
  • maven-assembly-plugin:single:个性化打包,用户可以自定义打包的类型打包的文件打包的目录结构等
  • spring-boot-maven-plugin:repackage在 jar 目标打包的基础上,将 compile、runtime 和 provided 的依赖打进 fat jar。

演示:

1、maven-jar-plugin:jar

  • 在父工程 maven-package-demo 中创建一个子模块 jar-project
  • 在 pom 文件中指定打包方式 packaging 为 jar(默认为 jar,所以可不指定)
  • 执行打包命令 mvn org.apache.maven.plugins:maven-jar-plugin:jar -pl :jar-project

执行流程如下:

xxx@xxxdeMacBook-Air maven-package-demo % mvn org.apache.maven.plugins:maven-jar-plugin:jar -pl :jar-project
[INFO] Scanning for projects...
[INFO] 
[INFO] ----------------------< cn.myphoenix:jar-project >----------------------
[INFO] Building jar-project 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- jar:3.4.1:jar (default-cli) @ jar-project ---
[WARNING] JAR will be empty - no content was marked for inclusion!
[INFO] Building jar: /Users/xxx/Code_Workspace/IDEA_Workspace/maven_project/maven-package-demo/jar-project/target/jar-project-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.313 s
[INFO] Finished at: 2024-12-24T21:06:43+08:00
[INFO] ------------------------------------------------------------------------

2、maven-war-plugin:war

  • 在父工程 maven-package-demo 中创建一个子模块 war-project
  • 在 pom 文件中指定打包方式 packaging 为 war
  • 执行打包命令 mvn org.apache.maven.plugins:maven-war-plugin:war -pl :war-project

执行流程如下:

xxx@xxxdeMacBook-Air maven-package-demo % mvn org.apache.maven.plugins:maven-war-plugin:war -pl :war-project
[INFO] Scanning for projects...
[INFO] 
[INFO] ----------------------< cn.myphoenix:war-project >----------------------
[INFO] Building war-project 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ war ]---------------------------------
[INFO] 
[INFO] --- war:3.4.0:war (default-cli) @ war-project ---
[INFO] Packaging webapp
[INFO] Assembling webapp [war-project] in [/Users/xxx/Code_Workspace/IDEA_Workspace/maven_project/maven-package-demo/war-project/target/war-project-1.0-SNAPSHOT]
[INFO] Processing war project
[INFO] Copying webapp resources [/Users/xxx/Code_Workspace/IDEA_Workspace/maven_project/maven-package-demo/war-project/src/main/webapp]
[INFO] Building war: /Users/xxx/Code_Workspace/IDEA_Workspace/maven_project/maven-package-demo/war-project/target/war-project-1.0-SNAPSHOT.war
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.355 s
[INFO] Finished at: 2024-12-24T21:14:44+08:00
[INFO] ------------------------------------------------------------------------

附:另外,我还将 war 的 packaging 声明删掉了,发现依然能够成功将模块打成 war 包。

3、maven-shade-plugin:shade

  • 在父工程 maven-package-demo 中创建一个子模块 shade-project
  • 在 pom 文件中引入 maven-shade-plugin 插件,并将其 shade 目标绑定到 package阶段
  • 在 pom 文件中引入 5 种依赖范围的依赖
  • 执行打包命令 mvn package -pl :shade-project

pom 文件中引入 maven-shade-plugin,并将 shade 目标绑定到 package 阶段

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.6.0</version>
        </plugin>
    </plugins>
</build>

pom 文件中引入的 5 种依赖范围的依赖,观察最终打成的 fat jar 中包含哪种类型的依赖:

<dependencies>
    <!-- compile 的依赖-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.16</version>
        <scope>compile</scope>
    </dependency>
    <!-- test 的依赖-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
    </dependency>
    <!-- provided 的依赖-->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>3.0-alpha-1</version>
        <scope>provided</scope>
    </dependency>
    <!-- runtime 的依赖-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.33</version>
        <scope>runtime</scope>
    </dependency>
    <!-- system 的依赖-->
    <dependency>
        <groupId>cn.myphoenix</groupId>
        <artifactId>big-marketing-wheel</artifactId>
        <version>1.0-SNAPSHOT</version>
        <scope>system</scope>
        <systemPath>/Users/xxx/desktop/big-marketing-wheel-1.0-SNAPSHOT.jar</systemPath>
    </dependency>
</dependencies>

命令的执行流程如下:

xxx@xxxdeMacBook-Air maven-package-demo % mvn package -pl shade-project
[INFO] Scanning for projects...
[INFO] 
[INFO] ---------------------< cn.myphoenix:shade-project >---------------------
[INFO] Building shade-project 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[WARNING] The artifact mysql:mysql-connector-java:jar:8.0.33 has been relocated to com.mysql:mysql-connector-j:jar:8.0.33: MySQL Connector/J artifacts moved to reverse-DNS compliant Maven 2+ coordinates.
[INFO] 
[INFO] --- resources:3.3.1:resources (default-resources) @ shade-project ---
[INFO] Copying 0 resource from src/main/resources to target/classes
[INFO] 
[INFO] --- compiler:3.13.0:compile (default-compile) @ shade-project ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 1 source file with javac [debug target 8] to target/classes
[INFO] 
[INFO] --- resources:3.3.1:testResources (default-testResources) @ shade-project ---
[INFO] skip non existing resourceDirectory /Users/xxx/Code_Workspace/IDEA_Workspace/maven_project/maven-package-demo/shade-project/src/test/resources
[INFO] 
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ shade-project ---
[INFO] Recompiling the module because of changed dependency.
[INFO] 
[INFO] --- surefire:3.2.5:test (default-test) @ shade-project ---
[INFO] 
[INFO] --- jar:3.4.1:jar (default-jar) @ shade-project ---
[INFO] Building jar: /Users/xxx/Code_Workspace/IDEA_Workspace/maven_project/maven-package-demo/shade-project/target/shade-project-1.0-SNAPSHOT.jar
[INFO] 
[INFO] --- shade:3.6.0:shade (default) @ shade-project ---
[INFO] Including org.mybatis:mybatis:jar:3.5.16 in the shaded jar.
[INFO] Including com.mysql:mysql-connector-j:jar:8.0.33 in the shaded jar.
[INFO] Including com.google.protobuf:protobuf-java:jar:3.21.9 in the shaded jar.
[INFO] Dependency-reduced POM written at: /Users/xxx/Code_Workspace/IDEA_Workspace/maven_project/maven-package-demo/shade-project/dependency-reduced-pom.xml
[WARNING] mybatis-3.5.16.jar, mysql-connector-j-8.0.33.jar, protobuf-java-3.21.9.jar, shade-project-1.0-SNAPSHOT.jar define 1 overlapping resource: 
[WARNING]   - META-INF/MANIFEST.MF
[WARNING] maven-shade-plugin has detected that some files are
[WARNING] present in two or more JARs. When this happens, only one
[WARNING] single version of the file is copied to the uber jar.
[WARNING] Usually this is not harmful and you can skip these warnings,
[WARNING] otherwise try to manually exclude artifacts based on
[WARNING] mvn dependency:tree -Ddetail=true and the above output.
[WARNING] See https://maven.apache.org/plugins/maven-shade-plugin/
[INFO] Replacing original artifact with shaded artifact.
[INFO] Replacing /Users/xxx/Code_Workspace/IDEA_Workspace/maven_project/maven-package-demo/shade-project/target/shade-project-1.0-SNAPSHOT.jar with /Users/xxx/Code_Workspace/IDEA_Workspace/maven_project/maven-package-demo/shade-project/target/shade-project-1.0-SNAPSHOT-shaded.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.254 s
[INFO] Finished at: 2024-12-25T15:05:30+08:00
[INFO] ------------------------------------------------------------------------

打成了两个 jar 包:

  • shade-project-1.0-SNAPSHOT.jar:shade 目标打成的包含依赖的 fat jar
  • original-shade-project-1.0-SNAPSHOT.jar:原本的 jar 目标打成的 jar 包
    在这里插入图片描述
    如标红处所示,将 compile 范围的 MyBatis 依赖和 runtime 范围的 MySQL 依赖打到了 fat jar 中。

附:

maven-shade-pluginshade 目标通常需要在 Maven 的 package 阶段执行,这意味着它依赖于之前阶段生成的主要构件(通常是 JAR 文件)。具体来说,在 shade 操作之前,Maven 必须已经构建并打包了项目的主类文件和资源文件到一个标准的 JAR 文件中。这是因为它的工作原理是基于这个主 JAR 文件,将所有依赖项合并到其中。

一、为什么 shade 需要先执行 jar

  • 主要构件的存在maven-shade-plugin 需要有一个基础的 JAR 文件来作为起点。这个 JAR 文件包含了编译后的项目代码和资源文件。如果 maven-jar-plugin 没有正确配置或没有被执行,那么就不会生成这个必要的主 JAR 文件,从而导致 shade 操作失败。
  • 生命周期顺序:Maven 的生命周期是有序的,每个阶段都有其特定的任务。package 阶段的任务就是创建可分发格式的包(如 JAR、WAR 等),而 maven-shade-pluginshade 目标则是对这些包进行进一步处理。因此,自然地,shade 应该在 package 阶段及之后执行,以确保它能够操作到已经生成好的主 JAR 文件。
  • 避免重复工作:直接从命令行调用 shade 可能会导致一些不必要的重复工作或者跳过某些重要的构建步骤。通过将 shade 绑定到 package 阶段,可以保证整个构建过程按照预期的顺序进行,不会遗漏任何关键步骤。

二、如何执行 shade 目标?

  • 配置插件绑定:在 pom.xml 中明确指定 maven-shade-pluginshade 目标绑定到 package 阶段,如下所示:
    • <build>
          <plugins>
              <plugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-shade-plugin</artifactId>
                  <version>3.2.4</version> <!-- 使用最新版本 -->
                  <executions>
                      <execution>
                          <phase>package</phase> <!-- 绑定到 package 阶段 -->
                          <goals>
                              <goal>shade</goal>
                          </goals>
                      </execution>
                  </executions>
              </plugin>
          </plugins>
      </build>
      
  • 运行完整的生命周期命令:使用像 mvn clean package 这样的命令来触发完整的构建过程,而不是直接尝试运行 shade 目标。这样可以确保所有必要的前期工作都已完成,并且 shade 操作可以顺利进行。

三、shade 目标会将哪些 scope 的依赖打进 fat jar?

  • 默认情况下,maven-shade-plugin 会将 compileruntime 范围的依赖打包进 Fat JAR 中,而不会包含 providedtestsystem 范围的依赖。上面实验也验证了这一点。

4、maven-assembly-plugin

实验设计

1、创建子模块如下图所示:

请添加图片描述
2、最终实现

  • 利用 single 目标生成一个名为 assembly-project-demo.zip 的压缩包
  • 将构建过程中生成的 jar 包打包进 assembly-project-demo.zip 的根目录下
  • 将 /resources/mybatis 目录下的 MyBatis 的 xml 配置文件打包进压缩包的 config/mybatis 目录下
  • 将 /resources 目录下的 application.properties 打包进压缩包的 config 目录下
  • 将 /resources/images 目录下的所有图片打包进压缩包的 config/images 目录下

使用 assembly 插件的步骤:

  • 构思确定打包的类型、需要打包的文件、最终包的目录结构
  • 在 pom 文件中引入 maven-assembly-plugin 插件。建议将 single 目标绑定到某一阶段如 package,当然也可以直接执行插件目标。
  • 编写配置文件
    • 需要打包的文件,如 jar 包、配置文件、资源文件等
    • 打包文件的放置目录,就是把某个文件放到最终包的某个目录下
  • 执行打包

实验步骤:

  • 在父工程 maven-package-demo 中创建一个子模块 assembly-project
  • 创建配置文件 src/main/assembly/assembly_config.xml,在配置文件配置打包的依赖、文件、jar 包等
  • 在 pom 文件中引入 maven-assembly-plugin 插件,并将其 single 目标绑定到 package阶段
  • 在 pom 文件中引入 4 种依赖范围的依赖
  • 执行打包命令 mvn package -pl :assembly-project

配置文件 assembly_config.xml 的内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<assembly>
    <!-- 最终打包文件的后缀,格式为 assembly-project-demo -->
    <id>demo</id>

    <!-- 最终打包成一个用于发布的zip文件 -->
    <formats>
        <format>zip</format>
    </formats>

    <!-- 把项目中依赖的 jar 包打进 assembly-project-demo.zip 压缩包的 lib 目录下 -->
    <dependencySets>
        <!-- 打包 runtime 类型的依赖 -->
        <dependencySet>
            <!-- 不使用项目的 artifact -->
            <useProjectArtifact>false</useProjectArtifact>
            <!-- 打包进 zip 文件下的 lib 目录中  -->
            <outputDirectory>lib</outputDirectory>
            <!-- 第三方 jar 不要解压 -->
            <unpack>false</unpack>
        </dependencySet>
    </dependencySets>

    <!-- 把项目中的文件打包进 assembly-project-demo.zip 压缩包 -->
    <fileSets>
        <!-- target 目录下的 jar 包打包进 assembly-project-demo.zip 压缩包的根目录下 -->
        <fileSet>
            <directory>target</directory>
            <outputDirectory>/</outputDirectory>
            <includes>
                <include>*.jar</include>
            </includes>
        </fileSet>

        <!-- /resources/mybatis 目录下的 MyBatis 的 xml 配置文件打包进 assembly-project-demo.zip 压缩包的 config/mybatis 目录中 -->
        <fileSet>
            <!-- 文件原始路径 -->
            <directory>${project.basedir}/src/main/resources/mybatis</directory>
            <!-- 文件打包目标路径 -->
            <outputDirectory>/config/mybatis</outputDirectory>
            <includes>
                <!-- 直接指定所有文件 -->
                <include>*.*</include>
            </includes>
        </fileSet>

        <!-- /resources 目录下的 application.properties 打包进 assembly-project-demo.zip 压缩包的 config 目录中 -->
        <fileSet>
            <directory>${project.basedir}/src/main/resources</directory>
            <outputDirectory>/config</outputDirectory>
            <includes>
                <include>*.properties</include>
            </includes>
        </fileSet>

        <!-- /resources/images 目录下的所有图片打包进 assembly-project-demo.zip 压缩包的 config/images 目录中 -->
        <fileSet>
            <directory>${project.build.directory}</directory>
            <outputDirectory>/config/images</outputDirectory>
            <includes>
                <include>*.jeg</include>
                <include>*.jpeg</include>
                <include>*.png</include>
            </includes>
        </fileSet>

    </fileSets>
</assembly>

pom 文件的主要配置如下:

<!-- 添加 4 种依赖范围的依赖 -->
<dependencies>
    <!-- compile 的依赖-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.16</version>
        <scope>compile</scope>
    </dependency>
    <!-- test 的依赖-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
    </dependency>
    <!-- provided 的依赖-->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>3.0-alpha-1</version>
        <scope>provided</scope>
    </dependency>
    <!-- runtime 的依赖-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.33</version>
        <scope>runtime</scope>
    </dependency>
</dependencies>

<!-- 配置 assembly 插件-->
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>3.2.0</version>
            <configuration>
                <!-- 配置打包后的文件前缀名 -->
                <finalName>assembly-project</finalName>
                <descriptors>
                    <!-- 指定配置文件的路径 -->
                    <descriptor>src/main/assembly/assembly_config.xml</descriptor>
                </descriptors>
            </configuration>
            <!-- 配置 assembly 的 goal -->
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

开始实验:

执行命令后,控制台打印如下:

xxx@xxxdeMacBook-Air maven-package-demo % mvn package -pl assembly-project
[INFO] Scanning for projects...
[INFO] 
[INFO] -------------------< cn.myphoenix:assembly-project >--------------------
[INFO] Building assembly-project 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[WARNING] The artifact mysql:mysql-connector-java:jar:8.0.33 has been relocated to com.mysql:mysql-connector-j:jar:8.0.33: MySQL Connector/J artifacts moved to reverse-DNS compliant Maven 2+ coordinates.
[INFO] 
[INFO] --- resources:3.3.1:resources (default-resources) @ assembly-project ---
[INFO] Copying 8 resources from src/main/resources to target/classes
[INFO] 
[INFO] --- compiler:3.13.0:compile (default-compile) @ assembly-project ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 2 source files with javac [debug target 8] to target/classes
[INFO] 
[INFO] --- resources:3.3.1:testResources (default-testResources) @ assembly-project ---
[INFO] skip non existing resourceDirectory /Users/xxx/Code_Workspace/IDEA_Workspace/maven_project/maven-package-demo/assembly-project/src/test/resources
[INFO] 
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ assembly-project ---
[INFO] Recompiling the module because of changed dependency.
[INFO] 
[INFO] --- surefire:3.2.5:test (default-test) @ assembly-project ---
[INFO] 
[INFO] --- jar:3.4.1:jar (default-jar) @ assembly-project ---
[INFO] Building jar: /Users/xxx/Code_Workspace/IDEA_Workspace/maven_project/maven-package-demo/assembly-project/target/assembly-project-1.0-SNAPSHOT.jar
[INFO] 
[INFO] --- assembly:3.2.0:single (make-assembly) @ assembly-project ---
[WARNING]  Parameter 'finalName' is read-only, must not be used in configuration
[INFO] Reading assembly descriptor: src/main/assembly/assembly_config.xml
[WARNING] The assembly descriptor contains a *nix-specific root-relative reference (starting with slash). This is not portable and might fail on Windows: /
[WARNING] The assembly descriptor contains a *nix-specific root-relative reference (starting with slash). This is not portable and might fail on Windows: /config/mybatis
[WARNING] The assembly descriptor contains a *nix-specific root-relative reference (starting with slash). This is not portable and might fail on Windows: /config
[WARNING] The assembly descriptor contains a *nix-specific root-relative reference (starting with slash). This is not portable and might fail on Windows: /config/images
[INFO] Building zip: /Users/xxx/Code_Workspace/IDEA_Workspace/maven_project/maven-package-demo/assembly-project/target/assembly-project-demo.zip
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.367 s
[INFO] Finished at: 2024-12-25T17:01:21+08:00
[INFO] ------------------------------------------------------------------------

说明:由绿色标注可以看到,assembly 的 single 目标在执行时,先读取了配置文件,然后构建了 zip 文件。

解压打成的 assembly-project-demo.zip 压缩包如下所示,可以看到和设计的目录结构一致:

请添加图片描述
说明:从 lib 目录可知,assembly:single 默认会将依赖范围是 compile 和 runtime 的依赖打进最终的归档文件。

我搜索的资料,说 maven-assembly-plugin 使用最多。比如大数据项目中往往有很多 shell 脚本、SQL 脚本、.properties 及 .xml 配置文件等,采用 assembly 插件可以自定义打包类型打包的文件打包的目录结构

  • assembly 插件的主要作用:允许用户将项目输出项与其依赖项、模块、站点文档、脚本或其他文件等一起组装成一个可分发的归档文件。换句话说,用户可以个性化、选择性、定制化的打包。
  • 最常用的标签:dependencySet 用来打包依赖;fileSet 用来打包文件。

参考:

  • https://maven.apache.org/plugins/maven-assembly-plugin/?spm=5176.28103460.0.0.2e935d27YS2Bey
  • https://maven.apache.org/plugins/maven-assembly-plugin/assembly.html
  • https://zhuanlan.zhihu.com/p/690199623
  • https://juejin.cn/post/6844904095245942798?searchId=20241225160224C56599BB59BAE97F66E5

5、spring-boot-maven-plugin

实验步骤:

  • 在父工程 maven-package-demo 中创建一个子模块 boot-maven-plugin-project
  • 在 pom 文件中引入 spring-boot-maven-plugin 插件
  • 在 pom 文件中引入 5 种依赖范围的依赖
  • 执行打包命令 mvn spring-boot:repackage -pl boot-maven-plugin-project

pom 文件中配置如下:

<properties>
    <main-class>com.myphoenix.MyApplication</main-class>
</properties>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>2.7.5</version>
            <configuration>
                <mainClass>${main-class}</mainClass>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

说明:

  • 标红:repackage 目标的执行需要借助于 maven-jar-plugin:jar。在此必须指定 repackage,然后执行命令 mvn package后会执行 repackage 目标。
  • 标绿:spring-boot-maven-plugin:repackage 的初衷是打一个可以运行的 fat jar,因此,建议配置好主程序类。

执行流程如下所示:

xxx@xxxdeMacBook-Air maven-package-demo % mvn package -pl boot-maven-plugin-project
[INFO] Scanning for projects...
[INFO] 
[INFO] ---------------< cn.myphoenix:boot-maven-plugin-project >---------------
[INFO] Building boot-maven-plugin-project 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[WARNING] The artifact mysql:mysql-connector-java:jar:8.0.33 has been relocated to com.mysql:mysql-connector-j:jar:8.0.33: MySQL Connector/J artifacts moved to reverse-DNS compliant Maven 2+ coordinates.
[INFO] 
[INFO] --- resources:3.3.1:resources (default-resources) @ boot-maven-plugin-project ---
[INFO] Copying 0 resource from src/main/resources to target/classes
[INFO] 
[INFO] --- compiler:3.13.0:compile (default-compile) @ boot-maven-plugin-project ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 3 source files with javac [debug target 8] to target/classes
[INFO] 
[INFO] --- resources:3.3.1:testResources (default-testResources) @ boot-maven-plugin-project ---
[INFO] skip non existing resourceDirectory /Users/xxx/Code_Workspace/IDEA_Workspace/maven_project/maven-package-demo/boot-maven-plugin-project/src/test/resources
[INFO] 
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ boot-maven-plugin-project ---
[INFO] Recompiling the module because of changed dependency.
[INFO] 
[INFO] --- surefire:3.2.5:test (default-test) @ boot-maven-plugin-project ---
[INFO] 
[INFO] --- jar:3.4.1:jar (default-jar) @ boot-maven-plugin-project ---
[INFO] Building jar: /Users/xxx/Code_Workspace/IDEA_Workspace/maven_project/maven-package-demo/boot-maven-plugin-project/target/boot-maven-plugin-project-1.0-SNAPSHOT.jar
[INFO] 
[INFO] --- spring-boot:2.7.5:repackage (default) @ boot-maven-plugin-project ---
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.928 s
[INFO] Finished at: 2024-12-25T18:20:09+08:00
[INFO] ------------------------------------------------------------------------

如下图所示,一共生成了两个包:

  • boot-maven-plugin-project-1.0-SNAPSHOT.jar:spring-boot-maven-plugin 打的 fat jar 包
  • boot-maven-plugin-project-1.0-SNAPSHOT.jar.original:maven-jar-plugin 打的普通 jar 包
    请添加图片描述
    打成的 fat jar 解压后结构如下图所示:
    请添加图片描述

说明:将依赖范围是 compile、runtime 和 provided 的依赖打包了,但 test 和 system 的依赖没有打包。

思考:既然 Maven 提供了多个打包插件,而且功能十分强大,为啥 Spring 官方还会再提供一个 spring-boot-maven-plugin 插件?

理解:即使 Maven 官方提供了多个插件,但是默认与生命周期绑定的只有 maven-jar-plugin,它的 jar 目标绑定到了 package 阶段上,只能打普通的 jar 包,无法直接运行。Spring Boot 倡导的一个理念是约定大于配置,其提供好了一些默认的配置。repackage 承袭了 Maven 的默认绑定,并且增强了 jar 目标。

本地文件jar包如何在pom文件里配置?

该题目的意思是,jar 包在自己的机器上,但是不在 Maven 的本地仓库中。所以,不能直接在 pom 文件中引入这个 jar 包。

解决方案

方案一:

  • 使用 scope 标签声明此 jar 包为系统级依赖
  • 使用 systemPath 标签指定 jar 包在本地机器上的路径

方案二:

使用mvn install:install-file命令将JAR包安装到本地Maven仓库。你需要提供JAR包的路径、组ID(groupId)、构件ID(artifactId)和版本号(version)。例如:

mvn install:install-file -Dfile=<path-to-file> -DgroupId=<group-id> -DartifactId=<artifact-id> -Dversion=<version> -Dpackaging=jar

附:Maven 的设计理念是所有依赖都应当通过仓库来管理,使用系统路径依赖项偏离了这一原则,可能会导致构建行为不可预测。

演示一:

创建一个项目,编写两个类,将项目打成 jar 包:

请添加图片描述
得到 jar 包 big-marketing-wheel-1.0-SNAPSHOT.jar,将此 jar 包放置到某个路径下,例如桌面 /Users/xxx/desktop/big-marketing-wheel-1.0-SNAPSHOT.jar。

可以看到,这个 jar 包并没有在本地仓库中,那么我们应该如何在项目中引入此 jar 包呢?

上面已经给出了解决方案。pom 文件配置如下:

<dependency>
    <groupId>cn.myphoenix</groupId>
    <artifactId>big-marketing-wheel</artifactId>
    <version>1.0-SNAPSHOT</version>
    <scope>system</scope>
    <systemPath>/Users/xxx/desktop/big-marketing-wheel-1.0-SNAPSHOT.jar</systemPath>
</dependency>

如下图所示,成功引入了位于桌面的 jar 包:

请添加图片描述

演示二:

将桌面上的 jar 包安装到本地仓库,然后直接在项目中导入本地仓库的 jar 包。

初始本地仓库中没有此 jar 包:

请添加图片描述
执行如下命令,将桌面上的 jar 包安装到本地仓库:

mvn install:install-file -Dfile=/Users/xxx/desktop/big-marketing-wheel-1.0-SNAPSHOT.jar -DgroupId=cn.myphoenix -DartifactId=big-marketing-wheel -Dversion=1.0-SNAPSHOT -Dpackaging=jar

执行流程如下:

xxx@xxxdeMacBook-Air sky-takeout % mvn install:install-file -Dfile=/Users/xxx/desktop/big-marketing-wheel-1.0-SNAPSHOT.jar -DgroupId=cn.myphoenix -DartifactId=big-marketing-wheel -Dversion=1.0-SNAPSHOT -Dpackaging=jar
[INFO] Scanning for projects...
[INFO] 
[INFO] ----------------------< cn.myphoenix:sky-takeout >----------------------
[INFO] Building sky-takeout 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- install:3.1.2:install-file (default-cli) @ sky-takeout ---
[INFO] Installing /Users/xxx/desktop/big-marketing-wheel-1.0-SNAPSHOT.jar to /Users/xxx/softwares/developer/apache-maven-3.9.9/repository/cn/myphoenix/big-marketing-wheel/1.0-SNAPSHOT/big-marketing-wheel-1.0-SNAPSHOT.jar
[INFO] Installing /var/folders/lw/_dqb_2nj2pzg16m_c06g9mf80000gn/T/big-marketing-wheel-1.0-SNAPSHOT3384356351638361494.pom to /Users/xxx/softwares/developer/apache-maven-3.9.9/repository/cn/myphoenix/big-marketing-wheel/1.0-SNAPSHOT/big-marketing-wheel-1.0-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.238 s
[INFO] Finished at: 2024-12-24T20:36:09+08:00
[INFO] ------------------------------------------------------------------------

如下图所示,成功将桌面上的 jar 包安装到本地仓库:

请添加图片描述

本文代码仓库:https://github.com/Acura-bit/maven-package-demo.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/943167.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

设备的分配与回收

目录 1、设备分配应考虑的因素 2、静态分配与动态分配 3、设备分配管理中的数据结构 &#xff08;1&#xff09;设备控制表 DCT &#xff08;2&#xff09;控制器控制表COCT &#xff08;3&#xff09;通道控制表CHCT &#xff08;4&#xff09;系统设备表SDT 4、分配过…

清空DNS 缓存

如果遇到修改了host文件&#xff0c;但是IP和域名的映射有问题的情况&#xff0c;可以尝试刷新DNS缓存。 ipconfig/flushdns win建加R建&#xff0c;然后输入cmd&#xff0c;然后回车 然后回车&#xff0c;或者点击确定按钮。 出现如下所示标识清空DNS 缓存成功。

Python使用requests_html库爬取掌阅书籍(附完整源码及使用说明)

教程概述 本教程先是幽络源初步教学分析掌阅书籍的网络结构&#xff0c;最后提供完整的爬取源码与使用说明&#xff0c;并展示结果&#xff0c;切记勿将本教程内容肆意非法使用。 原文链接&#xff1a;Python使用requests_html库爬取掌阅书籍&#xff08;附完整源码及使用说明…

Java爬虫实战:深度解析VIP商品详情获取技术

在数字化时代&#xff0c;数据的价值不言而喻。对于电商平台而言&#xff0c;掌握VIP商品的详细信息是提升服务质量、优化用户体验的关键。然而&#xff0c;这些信息往往被复杂的网页结构和反爬虫策略所保护。本文将带你深入了解如何使用Java编写爬虫&#xff0c;以安全、高效地…

硬件开发笔记(三十二):TPS54331电源设计(五):原理图BOM表导出、元器件封装核对

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/144753092 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

编程初学者使用 MariaDB 数据库反射生成

编程初学者使用 MariaDB 数据库反射生成 数据库反射生成&#xff0c;是动词算子式通用代码生成器提供的高级功能&#xff0c;可以利用已有的数据库&#xff0c;反射生成相应数据库的前端和后端项目。此功能自动化程度很高&#xff0c;并且支持完善的元数据和数据编辑&#xff…

机器人加装电主轴【铣削、钻孔、打磨、去毛刺】更高效

机器人加装电主轴进行铣削、钻孔、打磨、去毛刺等作业&#xff0c;展现出显著的优势&#xff0c;并能实现高效加工。 1. 高精度与高效率 电主轴特点&#xff1a;高速电主轴德国SycoTec的产品&#xff0c;转速可达100000rpm&#xff0c;功率范围广&#xff0c;精度≤1μm&#…

RCCL/NCCL中的Transports方式选择:P2P or SHM or NET

本篇文章主要总结以下在传输路径方式选择的时候&#xff0c;选择每一种方式应该满足的条件和优先度。 本文初步总结&#xff0c;之后还会进行更新&#xff0c;欢迎大家补充 源码位置&#xff1a;tools/topo_expl Topo结构&#xff1a; 初始化判断前 ret设置为0&#xff0c;代…

upload-labs关卡记录11

先上传一个一句话木马试试&#xff0c;居然可以上传成功&#xff0c;复制图片链接&#xff0c;在另一个窗口打开&#xff1a; 会发现&#xff0c;我们明明上传的是shell.php&#xff0c;但是这里就是没有了php,这样我们在执行我们相关的语句的时候就无法执行了&#xff1a; 就…

elementUI——upload限制图片或者文件只能上传一个——公开版

最近在写后台管理系统时&#xff0c;遇到一个需求&#xff0c;就是上传图片&#xff0c;有且仅能上传一张。 效果图如下&#xff1a; 功能描述&#xff1a;上传图片时&#xff0c;仅支持单选&#xff0c;如果上传图片成功后&#xff0c;展示图片&#xff0c;并隐藏添加图片的…

springboot餐厅点餐系统丨源码+数据库+万字文档+PPT

作者简介&#xff1a; 作者&#xff1a;学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等 文末获取“源码数据库万字文档PPT”&#xff0c;支持远程部署调试、运行安装。 技术框架 开发语言&#xff1a;Java 框架&#xff1a;springbo…

ArkTs组件(2)

一.下拉列表组件&#xff1a;Select 1.接口 Select(options: Array<SelectOption>) 参数名类型必填说明optionsArray<SelectOption>是设置下拉选项。 SelectOption对象说明 名称类型必填说明valueResourceStr是 下拉选项内容。 iconResourceStr否 下拉选项图片…

【MATLAB第110期】#保姆级教学 | 基于MATLAB的PAWN全局敏感性分析方法(无目标函数)含特征变量置信区间分析

【MATLAB第110期】#保姆级教学 | 基于MATLAB的PAWN全局敏感性分析方法&#xff08;无目标函数&#xff09;含特征变量置信区间分析 一、介绍 PAWN&#xff08;Probabilistic Analysis With Numerical Uncertainties&#xff09;是一种基于密度的全局敏感性分析&#xff08;Gl…

请购单一直提示需求部门不能为空无法提交

终于发现了它的逻辑。用户很多次反馈&#xff0c;提交请购单时&#xff0c;提示需求部门不能为空&#xff0c;既使选择了需求部门&#xff0c;保存时&#xff0c;神奇的是会清空掉部门的信息&#xff0c;提交时就会有错误提示出来。 原因&#xff1a;光选择单头上的需求部门是…

leetcode 面试经典 150 题:矩阵置零

链接矩阵置零题序号73题型二维数组解题方法标记数组法难度中等熟练度✅✅✅✅ 题目 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1]…

AIGC:生成图像动力学

文章目录 前言一、介绍二、方法2.1、运动预测模块运动纹理 2.2、图像渲染模块 三、数据集实验总结 前言 让静态的风景图能够动起来真的很有意思&#xff0c;不得不说CVPR2024 best paper实质名归&#xff0c;创意十足的一篇文章&#xff01;&#xff01;&#xff01; paper&a…

python: Oracle Stored Procedure query table

oracel sql script CREATE OR REPLACE PROCEDURE SelectSchool(paramSchoolId IN char,p_cursor OUT SYS_REFCURSOR ) AS BEGINOPEN p_cursor FORSELECT *FROM SchoolWHERE SchoolId paramSchoolId; END SelectSchool; /-- 查询所有 CREATE OR REPLACE PROCEDURE SelectScho…

社区版Dify 轻松实现文生图,Dify+LLM+ComfyUI

社区版Dify 轻松实文生图&#xff0c;DifyLLMComfyUI Dify 安装可参考这里ComfyUI 其实 比 WebUI更简单更实用DifyComfyUIDifyLLM1. Qwen 通义千问大模型系列2. OpenAI大模型系列3. 本地Ollama搭建 DifyLLMComfyUI Dify 安装可参考这里 这是一个在Dify上实现 文生图的教程&…

Docker部署Sentinel

一、简介 是什么&#xff1a;面向分布式、多语言异构化服务架构的流量治理组件 能干嘛&#xff1a;从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性 官网地址&#xff1a;https://sentinelguard.io/zh-c…

实用工具推荐----Doxygen使用方法

目录 目录 1 软件介绍 2 Doxygen软件下载方法 3 Doxygen软件配置方法 4 标准注释描述 4.1 块注释 和 特殊描述字符 4.1.1 函数描述示例 4.1.2结构体数组变量示例 特别注意&#xff1a; 4.2单行注释 4.2.1 单个变量注释示例 特别注意&#xff1a; 4.2.2对于枚举变量…