Maven打可運行jar包

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、要能加載到依賴包。
使用Maven有以下幾種方法可以生成能直接運行的jar包,可以根據需要選擇一種合適的方法。
方法一:使用maven-jar-plugin和maven-dependency-plugin插件打包
在pom.xml中配置:
<!-- 生成可執行JAR包命令 maven-jar-plugin -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <!-- 依賴jar包前綴 -->
                            <classpathPrefix>lib/</classpathPrefix>
                            <!-- Main入口 -->
                            <mainClass>*.spring.ui.Program</mainClass>
                        </manifest>
                        <manifestEntries>
                            <!-- classpath 路徑 -->
                            <Class-Path>./</Class-Path>
                        </manifestEntries>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                        <configuration>
                            <classifier>lib</classifier>
                            <excludes>
                                <exclude>*.xml</exclude>
                                <exclude>*.properties</exclude>
                            </excludes>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <!-- 拷貝依賴的jar包到lib目錄 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/lib</outputDirectory>
                            <overWriteReleases>false</overWriteReleases>
                            <overWriteSnapshots>false</overWriteSnapshots>
                            <overWriteIfNewer>true</overWriteIfNewer>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.3</version>
                <executions>
                    <execution>
                        <id>copy-resources</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <encoding>UTF-8</encoding>
                            <!-- 把配置文件拷到和jar包同一個路徑下 -->
                            <outputDirectory>${project.build.directory}</outputDirectory>
                            <resources>
                                <resource>
                                    <directory>src/main/resources/</directory>
                                    <!-- 對於有一層包無法copy到 -->
                                    <!--<includes>-->
                                    <!--<include>*.xml</include>-->
                                    <!--<include>*.properties</include>-->
                                    <!--</includes>-->
                                    <filtering>true</filtering>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
maven-jar-plugin用於生成META-INF/MANIFEST.MF文件的部分內容,<mainClass>*.spring.ui.Programe</mainClass>指定MANIFEST.MF中的Main-Class,<addClasspath>true</addClasspath>會在MANIFEST.MF加上Class-Path項並配置依賴包,<classpathPrefix>lib/</classpathPrefix>指定依賴包所在目錄,<Class-Path>./</Class-Path>指明classpath的路徑。
例如下面是一個通過maven-jar-plugin插件生成的MANIFEST.MF文件片段:
  1. Class-Path: ./ lib/commons-logging-1.2.jar lib/commons-io-2.4.jar  
  2. Main-Class: *.spring.ui.Programe  
只是生成MANIFEST.MF文件還不夠,maven-dependency-plugin插件用於將依賴包拷貝到<outputDirectory>${project.build.directory}/lib</outputDirectory>指定的位置,即lib目錄下。
配置完成後,通過mvn package指令打包,會在target目錄下生成jar包,並將依賴包拷貝到target/lib目錄下,目錄結構如下:

指定了Main-Class,有了依賴包,那麼就可以直接通過java -jar xxx.jar運行jar包。
這種方式生成jar包有個缺點,就是生成的jar包太多不便於管理,下面兩種方式只生成一個jar文件,包含項目本身的代碼、資源以及所有的依賴包。
方法二:使用maven-shade-plugin插件打包
在pom.xml中配置:
 <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.3</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <!-- 由於一些包重複引用,過濾打包後的 META-INF 目錄多出了一些 *.SF 等文件 -->
                            <filters>
                                <filter>
                                    <artifact>*:*</artifact>
                                    <excludes>
                                        <exclude>META-INF/*.SF</exclude>
                                        <exclude>META-INF/*.DSA</exclude>
                                        <exclude>META-INF/*.RSA</exclude>
                                    </excludes>
                                </filter>
                            </filters>
                            <transformers>
                                <!-- 打包jar文件時,配置manifest文件,加入程序入口mainClass -->
                                <transformer
                                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <manifestEntries>
                                        <mainClass>cn.richinfo.spring.ui.Program</mainClass>
                                        <Build-Number>123</Build-Number>
                                    </manifestEntries>
                                </transformer>
                                <!-- AppendingTransformer 指定當文件衝突時需要合併的文件 -->
                                <transformer
                                        implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                    <resource>META-INF/cxf/bus-extensions.txt</resource>
                                </transformer>
                                <transformer
                                        implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                    <resource>META-INF/spring.handlers</resource>
                                </transformer>
                                <transformer
                                        implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                    <resource>META-INF/spring.tooling</resource>
                                </transformer>
                                <transformer
                                        implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                    <resource>META-INF/spring.schemas</resource>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
配置完成後,執行mvn package即可打包。在target目錄下會生成兩個jar包,注意不是original-xxx.jar文件,而是另外一個。和maven-assembly-plugin一樣,生成的jar文件包含了所有依賴,所以可以直接運行。
如果項目中用到了Spring Framework,將依賴打到一個jar包中,運行時會出現讀取XML schema文件出錯。原因是Spring Framework的多個jar包中包含相同的文件spring.handlers和spring.schemas,如果生成一個jar包會互相覆蓋。爲了避免互相影響,所以使用AppendingTransformer來對文件內容追加合併。

總結:
Maven打可以直接運行的jar包有2中方式:
1、maven-jar-plugin和maven-resources-plugin插件配合可以分隔依賴包到獨立文件,但是不是一個整體的jar包。
2、maven-shade-plugin插件可以直接將依賴包整體集成一個jar包。
so.任君選擇-_-

發佈了34 篇原創文章 · 獲贊 13 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章