晚上写程序,引用了一个本地的jar包,使用Maven打成一个可执行的jar包,因为jar包没有导入到maven仓库中,好像导进去就没有那么多麻烦了。这里尝试了多种方式,想顺利执行jar文件,但是总是报NoClassDef的异常。来看下,本地加的jar在pom文件中是以system scope的方式提供的。
<dependency>
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
<version>2.5.1</version>
<scope>system</scope>
<systemPath>${basedir}/src/main/lib/objenesis-2.5.1.jar</systemPath>
</dependency>
(1)maven-assembly-plugin
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>org.zheng.proxy.objenesis.ObjenesisTest</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
这样结果是一个单独的jar包,把所有依赖jar以class文件的方式加了进去(比如spring,他就把spring解出来为class文件,不是原始打包的jar),但是没有看到我本地添加的那个jar的类被分解加入。
后来上网查了些资料,增加resource,可以把jar包引入,在pom.xml文件中添加
<resources>
<resource>
<targetPath>lib/</targetPath>
<directory>${basedir}/src/main/lib</directory>
<includes>
<include>*.jar</include>
</includes>
</resource>
</resources>
这样之后,
有了lib目录,算成功了一半了。可是执行仍然是NoClassDef。查看了下META-INF目录下的MANIFEST.MF文件
并没有引用这个jar包的声明。本来想增加Class-Path来包含这个jar。但是这个时候犯难了,这个ClassPath路径需要引的是jar包中lib的这个目录下的。从执行角度来看,这个地址是找不到的(因为没法先解包,至少没发现有相应方式)。
(2)maven-shade-plugin
结果执行效果和maven-assembly-plugin一样,不过从中学到了怎么额外指定Class-Path值,很重要,为后面的方案成功执行提供了重要帮助。这里指定的值,虽然不起作用:(
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>JavaProject-jar-with-dependencies</finalName>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.zheng.proxy.objenesis.ObjenesisTest</mainClass>
<manifestEntries>
<Class-Path>lib/objenesis-2.5.1.jar</Class-Path>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
(3)maven-jar-plugin + maven-dependency-plugin
<!--将依赖包另外放在一个目录引用-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib/</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
<manifestEntries>
<Class-Path>lib/objenesis-2.5.1.jar</Class-Path>
</manifestEntries>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>org.zheng.proxy.objenesis.ObjenesisTest</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
这样执行package后,可以看到所有依赖的包,单独输出在target/lib下面,还包含了输出的lib目录下包含了本地的那个jar包,
即使没有指定resource标签,也可以,原因是maven-dependency-plugin可以包含指定scope访问的jar包,默认为test,包含所有依赖。
因为在maven-jar-plugin中额外指定了ClassPath,所以现在的MANIFEST.MF文件有了这个jar的路径
运行的话,直接
java -jar JavaProject-1.0-SNAPSHOT.jar
终于搞定,研究了好久,高兴。