Maven打包所有依赖到一个可执行jar中

左手的ㄟ右手 2024-04-03 12:43 105阅读 0赞

文章目录

    • 需求
    • 遇到的问题
      • 找不到主类
      • 打包时没有包含第三方依赖
        • 情况1
        • 情况2
    • 扩展问题
      • 不希望依赖的jar包变成class
      • 项目里多个主类,如何动态指定

需求

普通的Maven Java项目(非Springboot项目),需要打包成一个jar包(包含所有的第三方依赖jar包),能够放在服务器上单独运行。

遇到的问题

找不到主类

大家都知道,如果使用常见的maven-jar-plugin打包,只能将自己项目里的源码编译打包,不会包含第三方的jar包。

如果该项目没有第三方依赖包,则可以通过maven-jar-plugin打包,直接执行打好的jar包(java -jar xxx.jar),可能会遇到找不到主类的情况,可以通过下面的方式解决:指定主类

  1. <plugin>
  2. <artifactId>maven-jar-plugin</artifactId>
  3. <version>3.0.2</version>
  4. <configuration>
  5. <archive>
  6. <manifest>
  7. <addClasspath>true</addClasspath>
  8. <mainClass>com.xxx.AppMain</mainClass>
  9. </manifest>
  10. </archive>
  11. </configuration>
  12. </plugin>

注意:

META-INF文件夹是MANIFEST.MF文件的主页。 此文件包含有关JAR内容的元数据。
JAR包中的/META-INF/MANIFEST.MF元数据文件必须包含Main-Class(主类)信息。(工程里的src/META-INF/MANIFEST.MF)
项目所有的依赖都必须在Classpath中,其可以通过 MANIFEST.MF 指定或者隐式设置。

打包时没有包含第三方依赖

如果该项目有第三方依赖包,通过上面的方式打包,是不会包含第三方依赖的,直接运行生成的jar包会出错(相关依赖不存在)。
想要打包时包含第三方依赖,又可以分两种情况:

情况1

打包成可执行jar文件,但是将所有依赖(包括外部依赖)单独打包到另外一个指定文件夹下,通过指定Class-Path的方式关联。

  1. 打包依赖到指定文件夹


    org.apache.maven.plugins
    maven-dependency-plugin
    2.10


    copy-dependencies
    package

    copy-dependencies


    ${project.build.directory}/lib



关于Maven dependency plugin可以参考我的另外一篇博客,有详细介绍:

Maven dependency plugin使用

  1. 指定启动入口,并关联依赖


    org.apache.maven.plugins
    maven-jar-plugin




    true

    lib/

    com.xxx.AppMain



配置好后,可以通过下面的命令编译打包:
mvn clean pacakge -DskipTests=true

注意,复杂情况下,classpath需要在运行时指定,如 java -cp …

情况2

将整个工程打成一个可执行jar包,包含所有的依赖。

需要通过maven-assembly-plugin插件来打包,可以实现该需求。

  1. <build>
  2. <plugins>
  3. <plugin>
  4. <artifactId>maven-compiler-plugin</artifactId>
  5. <version>2.3.2</version>
  6. <configuration>
  7. <source>1.8</source>
  8. <target>1.8</target>
  9. </configuration>
  10. </plugin>
  11. <plugin>
  12. <artifactId>maven-assembly-plugin</artifactId>
  13. <configuration>
  14. <descriptorRefs>
  15. <descriptorRef>jar-with-dependencies</descriptorRef>
  16. </descriptorRefs>
  17. <archive>
  18. <manifest>
  19. <mainClass>com.xxx.AppMain</mainClass>
  20. </manifest>
  21. </archive>
  22. </configuration>
  23. <executions>
  24. <execution>
  25. <id>make-assembly</id>
  26. <phase>package</phase>
  27. <goals>
  28. <goal>single</goal>
  29. </goals>
  30. </execution>
  31. </executions>
  32. </plugin>
  33. </plugins>
  34. </build>

配置好后,可以通过下面的命令编译打包:
mvn assembly:assembly
执行成功后会在target文件夹下多出一个以-jar-with-dependencies结尾的jar包. 这个jar包就包含了项目所依赖的所有jar的class

扩展问题

不希望依赖的jar包变成class

可以通过修改插件的配置做到

  1. 在本地maven仓库里找到maven-assembly-plugin

    cd ~/.m2/repository/org/apache/maven/plugins/maven-assembly-plugin/

  2. 进入打包时运行使用的版本里,如2.2-beta-5;

  3. 解压maven-assembly-plugin-2.2-beta-5.jar;
  4. 进入解压好的文件夹找到assemblies\jar-with-dependencies.xml,
    把里面的UNPACK改成FALSE,保存即可;
  5. 还原解压后的文件为jar包
    例如,在~/.m2/repository/org/apache/maven/plugins/maven-assembly-plugin/2.2-beta-5 路径里,执行下面的命令

    jar cvfm maven-assembly-plugin-2.2-beta-5.jar maven-assembly-plugin-2.2-beta-5/META-INF/MANIFEST.MF -C maven-assembly-plugin-2.2-beta-5 .

  6. 再次使用mvn assembly:assembly打包,编译好的以-jar-with-dependencies结尾的jar包. 这个jar包就包含了项目所依赖的所有jar文件,不再是class;

项目里多个主类,如何动态指定

可以通过自定义property属性,在执行maven命令时,动态指定来实现,配置如下:

例如,main.class 则为自定义的;

  1. <properties>
  2. <main.class>com.xxx.AppMain</main.class>
  3. </properties>
  4. <build>
  5. <plugins>
  6. <plugin>
  7. <artifactId>maven-compiler-plugin</artifactId>
  8. <version>2.3.2</version>
  9. <configuration>
  10. <source>1.8</source>
  11. <target>1.8</target>
  12. </configuration>
  13. </plugin>
  14. <plugin>
  15. <artifactId>maven-assembly-plugin</artifactId>
  16. <configuration>
  17. <descriptorRefs>
  18. <descriptorRef>jar-with-dependencies</descriptorRef>
  19. </descriptorRefs>
  20. <archive>
  21. <manifest>
  22. <mainClass>${main.class}</mainClass>
  23. </manifest>
  24. </archive>
  25. </configuration>
  26. <executions>
  27. <execution>
  28. <id>make-assembly</id>
  29. <phase>package</phase>
  30. <goals>
  31. <goal>single</goal>
  32. </goals>
  33. </execution>
  34. </executions>
  35. </plugin>
  36. </plugins>
  37. </build>

运行maven命令时,动态指定:

  1. mvn -Dmain.class=com.xxx.AppMain2 assembly:assembly

发表评论

表情:
评论列表 (有 0 条评论,105人围观)

还没有评论,来说两句吧...

相关阅读