在Jar包含相对路径的依赖

文章目录
  1. 1. 问题描述
  2. 2. 解决思路
    1. 2.1. 思路1:使用maven-shade-plugin
    2. 2.2. 思路2:使用maven-assembly-plugin
  3. 3. 总结

问题描述

今天在打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. 自定义项目仓库:
1
2
3
4
5
6
<repositories>
<repository>
<id>my</id>
<url>file://${basedir}/repo</url>
</repository>
</repositories>
  1. 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. 直接引用该依赖:
1
2
3
4
5
6
7
<dependencies>
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.4.2</version>
</dependency>
</dependencies>
  1. 使用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)。

需要注意的是,之所以不能使用以下的方式包含依赖,是因为scopesystem的依赖是不会被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