Maven 的打包方式

1,632 阅读3分钟

默认打包方式pom文件啥也不配置:

打包后目录结构如下:

仅打包项目中的代码到 JAR 包中,不打包依赖包,打包后的jar解压文件目录

# 先执行 clean,再执行 package,并且跳过测试用例的执行
mvn clean package -Dmaven.test.skip

项目的依赖都在maven中 的pom文件中无法独立运行

pom文件中添加名称可以修改打包后的jar名称
<build>    
   <finalName>idongjia</finalName>
</build>

第一种springboot项目将项目完整打包插件

<build>    
<finalName>idongjia</finalName>
    <plugins> 
       <plugin>  
          <groupId>org.springframework.boot</groupId> 
           <artifactId>spring-boot-maven-plugin</artifactId> 
       </plugin>
    </plugins>
</build>

打包后目录结构如下和MANIFEST.MF文件:

是可以使用 java -jar idongjia.jar 直接执行的

BOOT-INF是可运行jar包才有的,里面classes目录是咱们写的代码的classs文件,另一个lib就是其他依赖jar包的位置;

MANIFEST.MF文件

java -jar会去找jar中的MANIFEST.MF文件的Main-Class,在那里面找到真正的启动类;

使用spring-boot-maven-plugin插件用于将项目打包为可执行 Jar 包,不建议再使用其他任何插件

方法二:使用 maven-jar-plugin 和 maven-dependency-plugin 插件

<build>    
<!--项目打包成的名字-->    
<finalName>idongjia</finalName>   
 <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.6</version>
            <configuration>
                <archive>
                    <manifest>
                        <!--会在MANIFES.MF中生成Class-Path项目-->
                        <!--系统会根据Class-Path 项配置的路径加载依赖 -->
                        <addClasspath>true</addClasspath>
                        <!--指定依赖包所在目录,相对于项目最终Jar包的路径 -->
                        <classpathPrefix>lib/</classpathPrefix>
                        <!--指定MainClass -->
                        <mainClass>com.idongjia.MySpringBootApplication</mainClass> 
                   </manifest>
                </archive>
            </configuration>
        </plugin>
        <!--配置依赖包 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <version>2.10</version>
            <!--相当于执行mvn 命令将依赖包打包到指定目录 -->
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <!--将依赖包打包到target下的指定lib目录-->
                        <outputDirectory>${project.build.directory}/lib</outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

打包后的jar项目结构和对应的 MANIFEST.MF结构

首先说 maven-jar-plugin 插件,它的思想就是:指定启动类、指定依赖包相对于项目最终 Jar 包所在的路径、给 MANIFEST.MF 文件添加 Class-Path 属性(运行项目 Jar 包时会根据 Class-Path 属性来找到具体依赖 Jar 包的路径)。

 接着是 maven-dependency-plugin 插件,它的主要思想就是:指定所有依赖被打包为 Jar 包后的存放路径。 

# 先执行 clean,再执行 package,并且跳过测试用例的执行
mvn clean package -Dmaven.test.skip

打包完成后,会在项目的 target 目录下生成 lib 文件夹(存放项目的所有依赖)和项目的 Jar 包:

方法三:使用 maven-assembly-plugin 插件

    <build>
        <!-- 项目最终打包成的名字 -->
        <finalName>idongjia</finalName>

        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <archive>
                        <!-- 指定启动类 -->
                        <manifest>
                            <mainClass>com.idongjia.MySpringBootApplication</mainClass>                        </manifest>
                    </archive>
                    <!-- 指定启动类 -->
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>

                <!-- 相当于在执行 package 打包时,在后面加上 assembly:single  -->
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>

使用 maven-assembly-plugin 插件打出来的包只有一个 Jar 包

这个 Jar 包中包含了项目代码以及依赖的代码。可以直接通过 java -jar idongjia.jar 的命令来运行。

这个插件的使用思想也比较简单:首先还是指定启动类;然后配置描述符参数,这个是插件提供的预置参数,不用更改;接下来就是打包时追加的命令了。

然后执行 Maven 打包命令:

# 先执行 clean,再执行 package,并且跳过测试用例的执行
mvn clean package -Dmaven.test.skip

方法三:使用 maven-shade-plugin 插件

<build>        
<!-- 项目最终打包成的名字 -->        
<finalName>idongjia</finalName>        
<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>
                        <configuration>
                            <transformers>
                                  <!-- 下面的配置仅针对存在同名资源文件的情况,如没有则不用配置-->
                                    <!-- 有些项目包可能会包含同文件名的资源文件(例如属性文件)-->
                                    <!-- 为避免覆盖,可以将它们的内容合并到一个文件中 -->
                                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                        <resource>META-INF/spring.handlers</resource>
                                    </transformer>
                                    <transformer implementation="org.springframework.boot.maven.PropertiesMergingResourceTransformer">
                                        <resource>META-INF/spring.factories</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.ManifestResourceTransformer">
                                        <mainClass>com.idongjia.MySpringBootApplication</mainClass>
                                    </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
</build>

可以将项目的依赖以及项目的源码打包成一个可执行 Jar 包

指定项目的启动类;然后就是配置一个文件合并操作,主要是因为有的项目可能会有重名的资源文件,为了避免前面的资源文件被后面的覆盖掉,可以将重名的配置文件合并为一个文件,对于无重名资源文件的项目则无需配置。

# 先执行 clean,再执行 package,并且跳过测试用例的执行
mvn clean package -Dmaven.test.skip

打包后目录结构如下和MANIFEST.MF文件:

Spring Boot 的 Jar 包可以直接运行的原因:org.springframework.boot.loader.Launcher 类是 Spring Boot Jar 包实际的主类,负责调用应用的 main 方法。Launcher 类有三个子类:JarLauncherWarLauncherPropertiesLauncher,由它们负责从 jar 包或者 war 包中读取内嵌的资源

JarLauncherBOOT-INF/lib/ 固定路径加载资源;WarLauncher 是从 WEB-INF/lib/WEB-INF/lib-provided/ 路径。

PropertiesLauncher 默认从 BOOT-INF/lib/ 加载资源,并且支持通过环境变量 LOADER_PATHloader.path 来指定额外的路径。

具体的 Launcher 和应用的 main 函数所在类,设定在 MANIFEST.MF 文件中,一般由 Maven 或 Gradle 打包插件帮我们设定好,例如: