前提
Maven可以使用mvn package指令對項目進行打包,如果使用Java -jar xxx.jar執行運行jar文件,會出現"no main manifest attribute, in xxx.jar"(沒有設置Main-Class)、ClassNotFoundException(找不到依賴包)等錯誤。
要想jar包能直接通過java -jar xxx.jar運行,需要滿足:
1、在jar包中的META-INF/MANIFEST.MF中指定Main-Class,這樣才能確定程序的入口在哪里;
2、要能加載到依賴包。
搭建示例項目
1、新建Maven工程
2、編輯pom.xml文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <modelVersion>4.0.0</modelVersion> 6 7 <groupId>org.example</groupId> 8 <artifactId>test-mvn-package</artifactId> 9 <version>1.0-SNAPSHOT</version> 10 11 <dependencies> 12 <dependency> 13 <groupId>cn.hutool</groupId> 14 <artifactId>hutool-all</artifactId> 15 <version>5.3.7</version> 16 </dependency> 17 </dependencies> 18 </project>
3、編輯主類MyMain.java
1 public class MyMain { 2 3 public static void main(String[] args) { 4 System.out.println("===========程 序 啟 動==========="); 5 6 // 當前時間字符串,格式:yyyy-MM-dd HH:mm:ss 7 // DateUtil 第三方jar包中的類 8 String now = DateUtil.now(); 9 System.out.println("當前時間:" + now); 10 11 System.out.println("===========程 序 關 閉==========="); 12 } 13 }
4、測試,運行主方法,效果如下:
5、直接mvn package,打包后,運行jar包
運行方法一:java -jar test-mvn-package-1.0-SNAPSHOT.jar
運行方法二(指定主類):java -cp test-mvn-package-1.0-SNAPSHOT.jar com.test.api.MyMain
均無法直接運行
項目打包
使用Maven有以下幾種方法可以生成能直接運行的jar包,可以根據需要選擇一種合適的方法。
方法一:使用maven-jar-plugin和maven-dependency-plugin插件打包
1、在pom.xml中配置:
1 <build> 2 <plugins> 3 4 <!-- 使用maven-jar-plugin和maven-dependency-plugin插件打包 --> 5 <plugin> 6 <groupId>org.apache.maven.plugins</groupId> 7 <artifactId>maven-jar-plugin</artifactId> 8 <version>3.1.0</version> 9 <configuration> 10 <archive> 11 <manifest> 12 <addClasspath>true</addClasspath> 13 <classpathPrefix>lib/</classpathPrefix> 14 <mainClass>com.test.api.MyMain</mainClass> 15 </manifest> 16 </archive> 17 </configuration> 18 </plugin> 19 <plugin> 20 <groupId>org.apache.maven.plugins</groupId> 21 <artifactId>maven-dependency-plugin</artifactId> 22 <version>3.1.1</version> 23 <executions> 24 <execution> 25 <id>copy-dependencies</id> 26 <phase>package</phase> 27 <goals> 28 <goal>copy-dependencies</goal> 29 </goals> 30 <configuration> 31 <outputDirectory>${project.build.directory}/lib</outputDirectory> 32 </configuration> 33 </execution> 34 </executions> 35 </plugin> 36 37 </plugins> 38 </build>
說明:
maven-jar-plugin用於生成META-INF/MANIFEST.MF文件的部分內容,com.xx.Main指定MANIFEST.MF中的Main-Class,true會在MANIFEST.MF加上Class-Path項並配置依賴包,lib/指定依賴包所在目錄。
只是生成MANIFEST.MF文件還不夠,maven-dependency-plugin插件用於將依賴包拷貝到${project.build.directory}/lib指定的位置,即lib目錄下。
2、使用maven命令:mvn clean package 打包
3、target目錄內容如下,多了lib目錄
反編譯jar包,MANIFEST.MF文件內容如下:
4、使用命令:java -jar test-mvn-package-1.0-SNAPSHOT.jar,可以直接運行
方法二:使用maven-assembly-plugin插件打包
1、在pom.xml中配置:
1 <build> 2 <plugins> 3 4 <!-- 使用maven-assembly-plugin插件打包 --> 5 <plugin> 6 <groupId>org.apache.maven.plugins</groupId> 7 <artifactId>maven-assembly-plugin</artifactId> 8 <version>3.2.0</version> 9 <configuration> 10 <archive> 11 <manifest> 12 <mainClass>com.test.api.MyHttpRequest</mainClass> 13 </manifest> 14 </archive> 15 <descriptorRefs> 16 <descriptorRef>jar-with-dependencies</descriptorRef> 17 </descriptorRefs> 18 </configuration> 19 <executions> 20 <execution> 21 <id>make-assembly</id> 22 <phase>package</phase> 23 <goals> 24 <goal>single</goal> 25 </goals> 26 </execution> 27 </executions> 28 </plugin> 29 30 </plugins> 31 </build>
2、使用maven命令:mvn clean package 打包
3、target目錄內容如下,多了test-mvn-package-1.0-SNAPSHOT-jar-with-dependencies.jar包
反編譯jar包,test-mvn-package-1.0-SNAPSHOT-jar-with-dependencies.jar內容如下:
可以看到其中把第三方包的內容放到新的jar包中了
不過,如果項目中用到hutool-all第三方包,用這種方式打出來的包運行時可能會出錯,但實驗中沒有出現這種情況。項目中最好使用maven依賴源包
4、使用命令:java -jar test-mvn-package-1.0-SNAPSHOT.jar,無法運行
5、使用命令:java -jar test-mvn-package-1.0-SNAPSHOT-jar-with-dependencies.jar,可以直接運行
方法三:使用maven-shade-plugin插件打包
1、在pom.xml中配置:
1 <build> 2 <plugins> 3 4 <!-- 使用maven-shade-plugin插件打包 --> 5 <plugin> 6 <groupId>org.apache.maven.plugins</groupId> 7 <artifactId>maven-shade-plugin</artifactId> 8 <version>3.2.3</version> 9 <configuration> 10 <createDependencyReducedPom>false</createDependencyReducedPom> 11 </configuration> 12 <executions> 13 <execution> 14 <phase>package</phase> 15 <goals> 16 <goal>shade</goal> 17 </goals> 18 <configuration> 19 <transformers> 20 <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> 21 <mainClass>com.test.api.MyMain</mainClass> 22 </transformer> 23 </transformers> 24 </configuration> 25 </execution> 26 </executions> 27 </plugin> 28 29 </plugins> 30 </build>
2、使用maven命令:mvn clean package 打包
3、target目錄內容如下,多了original-test-mvn-package-1.0-SNAPSHOT.jar包
反編譯jar包,test-mvn-package-1.0-SNAPSHOT.jar內容如下:
可以看到其中把第三方包的內容放到新的jar包中了
不過,如果項目中用到hutool-all第三方包,用這種方式打出來的包運行時可能會出錯,但實驗中沒有出現這種情況。項目中最好使用maven依賴源包
4、使用命令:java -jar test-mvn-package-1.0-SNAPSHOT.jar