Maven打包方式

前言

关于使用maven将java代码打包成jar包,我之前一直是使用mvn package命令。不过也经常会遇到问题,例如打包的时候是依赖一起打包进来还是把依赖放在特定的目录,打包的时候指定主类等。所以我在网上找了一些文章,学习了一下maven打包的方式。

maven打包命令

首先使用maven打jar包最常用的命令就是mvn package,但是使用mvn installmvn deploy命令也都可以对项目进行打包,不过这几条命令都有区别:

  • mvn package:完成项目的编译、测试、打包
  • mvn install:完成项目的编译、测试、打包之后将打好的jar包部署到本地仓库
  • mvn deploy:完成项目的编译、测试、打包之后将打好的jar包部署到远程仓库

在完成打包之后使用java -jar命令运行jar包的时候很有可能会出现找不到主类清单的报错。这个时候也有两种解决方法,首先可以尝试使用java -cp命令:

1
java -cp xxx.jar [主类名称]

另一种方法是在META-INF\MANIFEST.MF文件中指定Main-Class的名称,这样在执行java -jar的时候就会根据MANIFEST.MFMain-Class的值找到要执行的类。然后我现在想让maven在打包的时候自动帮我在MANIFEST.MF文件中加上这个Main-Class

maven打包插件

maven常用的打包插件有主要有下面这几种

maven-jar-pluginmaven-dependency-plugin

maven-jar-pluginmaven-dependency-plugin是默认的打包插件

  • maven-jar-plugin负责将项目打包成jar包,并且可以给MANIFEST.MF加上一些自定义的属性,例如Main-Class用于指定启动类,Class-Path由于指定去哪个路径找依赖包
  • maven-dependency-plugin就是负责处理依赖包的,它可以指定打包后项目中使用到的依赖包需要放在哪个目录

一般情况下maven-jar-pluginmaven-dependency-plugin会同时使用。

然后怎么使用maven-jar-pluginmaven-dependency-plugin呢,这里有几个例子理解maven-jar-pluginmaven-dependency-plugin打包,并向其中添加Main-Class属性。

  1. 指定manifestFile

    首先可以尝试自己创建一个META-INF/MANIFEST.MF文件,然后向其中添加Main-Class属性:

    1
    
    Main-Class: org.e4stjun.Main
    

    接着在pom.xml文件中用manifestFile指定MANIFEST.MF文件的路径,在打包后就会把MANIFEST.MF文件打包进去,如果有其他属性要加进来的话会追加:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    <build>
        <!--        指定打包后的文件名-->
        <finalName>Mavencmd-1.0-SNAPSHOT</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.3.0</version>
                <configuration>
                    <archive>
                        <manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
    
  2. pom.xml里面添加manifest属性

    这样子就是说通过标签向MANIFEST.MF添加一些属性,不用自己创建了,让maven自动帮我创建

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.3.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>org.e4stjun.Main</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
    
  3. 打包时将依赖复制到lib目录:

    如果项目中引入了一些依赖的话就需要同时使用maven-jar-pluginmaven-dependency-plugin两个插件了,maven-jar-plugin中指定主类,除此之外还要告诉jar包去哪个目录找引入依赖的jar包,而maven-dependency-plugin将项目依赖的jar包复制到指定目录,例如在这个例子里面打包的jar包去./lib目录找到依赖包,maven-dependency-plugin将依赖复制到输出目录的lib文件夹中:

     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
    
    <build>
        <finalName>Mavencmd-1.0-SNAPSHOT</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.3.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <!-- 指定主类 -->
                            <mainClass>org.e4stjun.Main</mainClass>
                            <!-- 是否指定项目classpath下的依赖 -->
                            <addClasspath>true</addClasspath>
                            <!-- 指定依赖的时候声明前缀 -->
                            <classpathPrefix>./lib/</classpathPrefix>
                            <!--依赖是否使用带有时间戳的唯一版本号,如:xxx-1.3.0-20121225.012733.jar-->
                            <useUniqueVersions>false</useUniqueVersions>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>3.6.0</version>
                <executions>
                    <execution>
                        <id>copy</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/lib</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    

maven-assembly-plugin

这个插件打包出来的只有一个jar包,可以通过java -jar直接执行,

  1. 使用mvn package assembly:single命令打包:

    同样还是先要指定Main-Class,然后打包完会在输出文件夹中生成一个xxx-jar-with-dependencies.jar文件,包含项目中所有的依赖,通过java -jar命令可以直接执行:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.6.0</version>
                <configuration>
                    <archive>
                        <!-- 指定启动类 -->
                        <manifest>
                            <mainClass>org.e4stjun.Main</mainClass>
                        </manifest>
                    </archive>
                    <!-- Maven预配置的描述符 -->
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
            </plugin>
        </plugins>
    </build>
    
  2. mvn package打包,不加assembly:single参数:

    这样的话需要再多写一个execution 块:

     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
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.6.0</version>
                <configuration>
                    <archive>
                        <!-- 指定启动类 -->
                        <manifest>
                            <mainClass>org.e4stjun.Main</mainClass>
                        </manifest>
                    </archive>
                    <!-- Maven预配置的描述符 -->
                    <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>
        </plugins>
    </build>
    
  3. 引入assembly.xml描述文件

    还有一种是在pom.xml文件中引入assembly.xml描述文件:

    1
    2
    3
    4
    5
    
    <configuration>
    	<descriptors>
    		<descriptor>src/main/assembly/assembly.xml</descriptor>
    	</descriptors>
    </configuration>
    

    maven官方的文档在这里:https://maven.apache.org/plugins/maven-assembly-plugin/assembly.html

    在某一个场景下,我需要将scope为system的依赖打包进jar包这个时候我需要在assembly.xml描述文件中添加这一段:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    <assembly xmlns="http://maven.apache.org/ASSEMBLY/2.2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.2.0 https://maven.apache.org/xsd/assembly-2.2.0.xsd">
        <id>jar-with-all-dependencies</id>
        <formats>
            <format>jar</format>
        </formats>
        <includeBaseDirectory>false</includeBaseDirectory>
        <dependencySets>
            <dependencySet>
                <outputDirectory>/</outputDirectory>
                <useProjectArtifact>true</useProjectArtifact>
                <unpack>true</unpack>
                <scope>runtime</scope>
            </dependencySet>
            <dependencySet>
                <outputDirectory>/</outputDirectory>
                <unpack>true</unpack>
                <scope>system</scope>
            </dependencySet>
        </dependencySets>
    </assembly>
    

    在使用maven打包的时候就会将需要的jar包也打包进去了。

maven-shade-plugin

maven-shade-plugin也是一个很强大的打包插件,主要是可以用来处理依赖冲突的问题,这里我给一个例子出来:

 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
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.5.0</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <transformers>
                            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <!-- 指定启动类 -->
                                <!--<mainClass>org.e4stjun.Main</mainClass>-->
                                <manifestEntries>
                                    <Main-Class>org.e4stjun.Main</Main-Class>
                                </manifestEntries>
                            </transformer>
                        </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Referer

maven打包详解,不同打包插件的区别及适用场景

updatedupdated2023-09-062023-09-06