问题描述
今天在打jar包的时候遇到了一点问题:我要把一个attach jvm功能的jar包打成一个可执行文件,该jar包依赖了jdk中的tools.jar。
打包时我用了maven-shade-plugin插件,但是在运行(java -jar xxx.jar)时,却出现了如下异常: java.lang.ClassNotFoundException:com.sun.tools.attach.AttachNotSupportedException
很明显tools.jar没有找到,所以需要显示地制定classpath,于是,执行下面命令:java -cp ${JAVA_HOME}/lib/tools.jar:xxxx.jar mail.class.name
可以顺利执行。
但是这个过程中我使用了JAVA_HOME变量,同时也不能用java -jar xxxx.jar命令,所以需要继续改进。
直接的思路就是把tools.jar包含在项目里。
通过一系列尝试,有下面两个方案可以实现此需求:
解决思路
思路1:使用maven-shade-plugin
- 自定义项目仓库:
1 2 3 4 5 6
| <repositories> <repository> <id>my</id> <url>file://${basedir}/repo</url> </repository> </repositories>
|
- 把tools.jar安装在项目仓库;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-install-plugin</artifactId> <version>2.3.1</version> <executions> <execution> <phase>clean</phase> <goals> <goal>install-file</goal> </goals> <configuration> <groupId>com.sun</groupId> <artifactId>tools</artifactId> <version>1.4.2</version> <packaging>jar</packaging> <localRepositoryPath>//${basedir}/repo</localRepositoryPath> <file>${java.home}/../lib/tools.jar</file> </configuration> </execution> </executions> </plugin>
|
- 直接引用该依赖:
1 2 3 4 5 6 7
| <dependencies> <dependency> <groupId>com.sun</groupId> <artifactId>tools</artifactId> <version>1.4.2</version> </dependency> </dependencies>
|
- 使用maven-shade-plugin打包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>2.4.3</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <minimizeJar>true</minimizeJar> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>mainClass</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin>
|
思路2:使用maven-assembly-plugin
plugin配置
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
| <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>2.4</version>
<configuration> <appendAssemblyId>false</appendAssemblyId> <descriptors> <descriptor>src/main/assemble/package.xml</descriptor> </descriptors> <archive> <manifest> <mainClass>mainClass</mainClass> </manifest> </archive> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin>
|
package.xml配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"> <id>jar-with-all-dependencies</id> <formats> <format>jar</format> </formats> <includeBaseDirectory>false</includeBaseDirectory> <dependencySets> <dependencySet> <outputDirectory>/</outputDirectory> <useProjectArtifact>true</useProjectArtifact> <unpack>true</unpack> <scope>runtime</scope> </dependencySet> <dependencySet> <outputDirectory>/</outputDirectory> <unpack>true</unpack> <scope>system</scope> </dependencySet> </dependencySets>
</assembly>
|
总结
在思路2中,由于maven-assembly-plugin没有压缩jar包,因此最终产生的jar包较大(6M),而使用maven-shade-plugin打的包,由于有minimizeJar配置,因此最终产生的包较小(150KB)。
需要注意的是,之所以不能使用以下的方式包含依赖,是因为scope为system的依赖是不会被maven-shade-plugin包含的,即下面的用法是无效的:
1 2 3 4 5 6 7
| <dependency> <groupId>com.sun</groupId> <artifactId>tools</artifactId> <systemPath>${java.home}/../lib/tools.jar</systemPath> <scope>system</scope> <version>1.4.2</version> </dependency>
|
最终使用第一种方法产生的jar包具有的优点是:
1. 生成的jar包大小合适;
2. 包含了所需要的所有依赖;
3. 可直接使用*java -jar*执行。
参考:Maven: add a dependency to a jar by relative path