Maven 工程生成可执行的 JAR 包

远离 Maven 工程有些时日了,也不知道当前还是否在流行 Maven 管理工程与依赖,当前类似工具有 Ant+Ivy, Grunt, sbtGradle。Web 工程的输出发布包没什么好说的,因为 <packaging>war</packaging>,所以 mvn package 出来的 WAR 包里就有站点运行的所有内容了,用到的依赖会在 WEB-INF/lib 目录下列着。


而对于那些 <packaging>jar</packaging> 的工程,用 mvn package 只会生成一个 JAR 包,它所依赖的各个类库仍然分散在本地仓库中,而我们的发布包应该包含这些第三方依赖的。

假定,有一个 GoSSH  Maven 工程,设定的版本是 0.0.1,它依赖了 jsch-0.1.50, commons-cli-1.3-SNAPSHOT,想要发布的包有如下布局
GoSSH-0.0.1.jar
lib
        jsch-0.1.50.jar
        commons-cli-1.3-20140216.032825-101.jar     #这里的 revision 号是随 SNAPSHOT 动态而定的
并且在 GoSSH-0.0.1.jar 中的 META-INF/MANIFEST.MF 文件中指定了
Class-Path: lib/jsch-0.1.50.jar lib/commons-cli-1.3-20140216.032825-101.jar
Main-Class: cc.unmi.Main
想要的效果就是可以用命令
java -jar GoSSH-0.0.1.jar
直接执行 为了这个需求我们可以使用 maven-jar-pluginmaven-dependency-plugin 这两个插件。它有许多的 Goal,这里是我自己的一个配置片断
 1    <build>
 2        <plugins>
 3            <plugin>
 4                <groupId>org.apache.maven.plugins</groupId>
 5                <artifactId>maven-jar-plugin</artifactId>
 6                <version>2.4</version>
 7                <configuration>
 8                    <archive>
 9                        <manifest>
10                            <addClasspath>true</addClasspath>
11                            <classpathPrefix>lib/</classpathPrefix>
12                            <mainClass>cc.unmi.Main</mainClass>
13                        </manifest>
14                    </archive>
15                </configuration>
16            </plugin>
17            <plugin>
18                <groupId>org.apache.maven.plugins</groupId>
19                <artifactId>maven-dependency-plugin</artifactId>
20                <executions>
21                    <execution>
22                        <id>copy-dependencies</id>
23                        <phase>pre-package</phase>
24                        <goals>
25                            <goal>copy</goal>
26                        </goals>
27                        <configuration>
28                            <artifactItems>
29                                <artifactItem>
30                                    <groupId>com.jcraft</groupId>
31                                    <artifactId>jsch</artifactId>
32                                    <version>0.1.50</version>
33                                    <outputDirectory>${project.build.directory}/lib</outputDirectory>
34                                    <overWrite>true</overWrite>
35                                </artifactItem>
36                                <artifactItem>
37                                    <groupId>commons-cli</groupId>
38                                    <artifactId>commons-cli</artifactId>
39                                    <version>1.3-SNAPSHOT</version>
40                                    <outputDirectory>${project.build.directory}/lib</outputDirectory>
41                                    <overWrite>true</overWrite>
42                                </artifactItem>
43                            </artifactItems>
44                        </configuration>
45                    </execution>
46                </executions>
47            </plugin>
48        ......
49        </plugins>

看到上面那段代码一眼就能看出它们正在做什么,对,要用到的需拷贝到 lib 目录中的依赖包配置成 <artifactItem>,以后执行 mvn package 时就会生成前面的目录布局,GoSSH-0.0.1.jar 和 lib/jsch-0.1.50.jar 和 lib/commons-cli-1.3-20140216.032825-101.jar。这就是我们要的发布包的内容。

另外,我们只借助于插件 maven-assembly-plugin 能做出一个包含了依赖类的独立的 JAR 包,比如生成的 GoSSH-0.0.1-jar-with-dependencies.jar,内含在 <dependencies> 中配置的运行时依赖,它们不再以一个个 JAR 各自存在,而是全部内容都在那个 xxx-with-dependencies.jar 中的。

这时候的配置是
 1    <build>
 2        <plugins>
 3           <plugin>
 4                <!-- mvn assembly:single -->
 5                <groupId>org.apache.maven.plugins</groupId>
 6                <artifactId>maven-assembly-plugin</artifactId>
 7                <configuration>
 8                    <descriptorRefs>
 9                        <descriptorRef>jar-with-dependencies</descriptorRef>
10                    </descriptorRefs>
11                    <archive>
12                        <manifest>
13                            <mainClass>cc.unmi.Main</mainClass>
14                        </manifest>
15                    </archive>
16                </configuration>
17                <executions>  <!-- 这部分配置只是为了把任务绑定到 package -->
18                    <execution>
19                        <id>make-assembly</id>
20                        <phase>package</phase>
21                        <goals>
22                            <goal>single</goal>
23                        </goals>
24                    </execution>
25                </executions>
26            </plugin>
27        ......
28        </plugins>

这样在执行 mvn package 或 mvn assembly:single 就会生成 GoSSH-0.0.1-jar-with-dependencies.jar,发布的时候只需要这一个文件就行了。但这样做其实有些不太好,自己的类与依赖类混在一起,不知道依赖了哪些包,可能这个无依赖的包会很大。

更多的配置细节,还得去浏览以上所提到的三个插件官网上的帮助。 永久链接 https://yanbin.blog/maven-generate-executable-jar/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。