远离 Maven 工程有些时日了,也不知道当前还是否在流行 Maven 管理工程与依赖,当前类似工具有 Ant+Ivy, Grunt, sbt 和 Gradle。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-plugin 和 maven-dependency-plugin 这两个插件。它有许多的 Goal,这里是我自己的一个配置片断
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.4</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> <mainClass>cc.unmi.Main</mainClass> </manifest> </archive> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>copy-dependencies</id> <phase>pre-package</phase> <goals> <goal>copy</goal> </goals> <configuration> <artifactItems> <artifactItem> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.50</version> <outputDirectory>${project.build.directory}/lib</outputDirectory> <overWrite>true</overWrite> </artifactItem> <artifactItem> <groupId>commons-cli</groupId> <artifactId>commons-cli</artifactId> <version>1.3-SNAPSHOT</version> <outputDirectory>${project.build.directory}/lib</outputDirectory> <overWrite>true</overWrite> </artifactItem> </artifactItems> </configuration> </execution> </executions> </plugin> ...... </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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<build> <plugins> <plugin> <!-- mvn assembly:single --> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> <archive> <manifest> <mainClass>cc.unmi.Main</mainClass> </manifest> </archive> </configuration> <executions> <!-- 这部分配置只是为了把任务绑定到 package --> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> ...... </plugins |
这样在执行 mvn package 或 mvn assembly:single 就会生成 GoSSH-0.0.1-jar-with-dependencies.jar,发布的时候只需要这一个文件就行了。但这样做其实有些不太好,自己的类与依赖类混在一起,不知道依赖了哪些包,可能这个无依赖的包会很大。
更多的配置细节,还得去浏览以上所提到的三个插件官网上的帮助。
本文链接 https://yanbin.blog/maven-generate-executable-jar/, 来自 隔叶黄莺 Yanbin Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。