Maven如何打包可执行jar包

方法一:使用maven-jar-pluginmaven-dependency-plugin

1、单独使用maven-jar-plugin不做核外配置,直接打包出现的问题

2、配置mainClass和指定classpath

    <build>
        <plugins>
            <!--maven-jar-plugin的作用是配置mainClass和指定classpath。-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <!--是否在manifest文件中添加classpath。默认为false。-->
                            <addClasspath>true</addClasspath>
                            <!--指定类路径前缀,也就是依赖的jar包所在的文件夹-->
                            <classpathPrefix>lib/</classpathPrefix>
                            <!--指定启动类-->
                            <mainClass>org.example.Application</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>

>>> 打包后的jar包目录结构为:

META-INF
    |- MANIFEST.MF
    |- maven
        |- org.example
            |- maven-test
                    |- pom.properties
                    |- pom.xml
             
org.example
    |- controller
            |- HelloController.class 
    |- Application.class

jdbc.properties

>>> 查看META-INF/MANIFEST.MF文件,可以看到我们的配置信息:

Manifest-Version: 1.0
Implementation-Title: maven-test
Implementation-Version: 1.0-SNAPSHOT
Class-Path: lib/spring-boot-starter-web-2.1.16.RELEASE.jar lib/spring-
 boot-starter-2.1.16.RELEASE.jar lib/spring-boot-starter-logging-2.1.1
 6.RELEASE.jar lib/logback-classic-1.2.3.jar lib/logback-core-1.2.3.ja
 r lib/slf4j-api-1.7.30.jar lib/log4j-to-slf4j-2.11.2.jar lib/log4j-ap
 i-2.11.2.jar lib/jul-to-slf4j-1.7.30.jar lib/javax.annotation-api-1.3
 .2.jar lib/spring-core-5.1.17.RELEASE.jar lib/spring-jcl-5.1.17.RELEA
 SE.jar lib/snakeyaml-1.23.jar lib/spring-boot-starter-json-2.1.16.REL
 EASE.jar lib/jackson-databind-2.9.10.5.jar lib/jackson-annotations-2.
 9.10.jar lib/jackson-core-2.9.10.jar lib/jackson-datatype-jdk8-2.9.10
 .jar lib/jackson-datatype-jsr310-2.9.10.jar lib/jackson-module-parame
 ter-names-2.9.10.jar lib/spring-boot-starter-tomcat-2.1.16.RELEASE.ja
 r lib/tomcat-embed-core-9.0.37.jar lib/tomcat-embed-el-9.0.37.jar lib
 /tomcat-embed-websocket-9.0.37.jar lib/hibernate-validator-6.0.20.Fin
 al.jar lib/validation-api-2.0.1.Final.jar lib/jboss-logging-3.3.3.Fin
 al.jar lib/classmate-1.4.0.jar lib/spring-web-5.1.17.RELEASE.jar lib/
 spring-beans-5.1.17.RELEASE.jar lib/spring-webmvc-5.1.17.RELEASE.jar 
 lib/spring-aop-5.1.17.RELEASE.jar lib/spring-context-5.1.17.RELEASE.j
 ar lib/spring-expression-5.1.17.RELEASE.jar lib/spring-boot-autoconfi
 gure-2.1.16.RELEASE.jar lib/spring-boot-2.1.16.RELEASE.jar
Build-Jdk-Spec: 1.8
Created-By: Maven Archiver 3.4.0
Main-Class: org.example.Application

>>> 此时,我们运行该jar包,还是报错:

3、添加maven-dependency-plugin依赖

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>
                    ${project.build.directory}/lib
                </outputDirectory>
            </configuration>
        </execution>
    </executions>
</plugin>
executions中的配置都很重要,按照上面的配置来就行了。outputDirectory指定了要将所依赖的jar包copy到哪个目录,要与maven-jar-plugin中的classpathPrefix一致。
 
>>> 再次打包后, target目录信息如下图:
 
 
发现可以成功运行该jar包了:
 

4、发现的问题

当我们单独把jar包拎出来运行时,还是会出现步骤2中的错误,这是因为根据<classpathPrefix>lib/</classpathPrefix>配置,程序默认会在 maven-test-1.0-SNAPSHOT.jar 包所在的目录下查询 lib/ 下的依赖

此时如果单独移动jar运行就会缺少依赖,程序无法执行。还需要把 lib 文件夹复制粘贴到与 maven-test-1.0-SNAPSHOT.jar 同级目录下。

优点
有诸多配置项,很自由,每个步骤都可控

缺点
打成的最终jar包中没有所依赖的jar包。依赖跟自己的代码不在一个jar包中。部署或者移动的时候,要考虑到多个文件,比较麻烦


方法二:使用spring-boot-maven-plugin

1、去除方法一的依赖,添加如下依赖

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

Spring Boot Maven Plugin提供了Spring Boot的Maven支持,允许你打包可执行文件和war文件,并且就地运行。

Spring Boot Plugin有如下目标:

  • spring-boot:help | 展示spring-boot-maven-plugin的帮助信息,使用 mvn spring-boot:help -Ddetail=true -Dgoal=<goal-name>展示参数详情 
  • spring-boot:repackage | 重新打包存在的jar或者war包从而使他们可以在命令行使用jar -jar来执行,使用layout=NONE也可以简单的打包有嵌套依赖的jar(没有主类,所以无法执行)
  • spring-boot:run | 运行一个可执行的应用(相当于我们手动运行springboot启动类)
  • spring-boot:start | 启动Spring应用程序。和run目标不同,该目标不会阻塞,并且允许其他目标来操作应用程序。这个目标通常是在应用程序集成测试套件开始之前和停止之后的继承测试脚本中使用
  • spring-boot:stop | 停止使用start目标启动的spring应用程序,通常在测试套件完成后被调用。

2、jar包的差异

采用方法一打包只会在 target 目录下 生成一个 maven-test-1.0-SNAPSHOT.jar,而使用 Spring Boot Maven Plugin 的话,导入依赖后不用做其他的配置,直接运行 mvn:package,maven运行结果如下图所示:

由此可知,我们执行打包命令后,Spring Boot Maven Plugin 会将 maven-jar-plugin 生成的jar包 进行二次打包【目的就是解决方法一中出现的问题】

此时会发现在target目录下生成了两个压缩文件:

  • maven-test-1.0-SNAPSHOT.jar  【二次打包的版本】
  • maven-test-1.0-SNAPSHOT.jar.original  【初始版本,无法直接使用 java -jar来执行】

 >>> 对比两个压缩文件,可以发现二次打包后的jar包多出一个 BOOT-INF 目录,且jdbc.proerties配置文件不见了:

>>> 进入BOOT-INF目录,可以发现我们的代码和依赖的jar都被放入到该目录了,jdbc配置文件也被移动到了其子目录classes下:

3、项目中多个springboot模块之间存在依赖

我们知道如果项目的模块之间存在依赖,我们在打包的时候必须先把被依赖的模块 install 到本地仓库中,其他依赖于它的模块才能成功打包运行。

【此处有坑】

安装到本地仓库的jar包不能是二次打包的版本。最简单的解决方法就是在 install 前注释掉 Spring Boot Maven Plugin 依赖即可

 

posted @ 2022-09-29 11:30  danielzzz  阅读(4790)  评论(0编辑  收藏  举报