最近在使用maven生成可执行的jar包的时候,遇到了个问题,当然maven生成runnable的jar包有很多种方式:
- maven-jar-plugin和maven-dependency-plugin插件打包
- maven-assembly-plugin插件打包
- 使用maven-shade-plugin插件打包
本博文研究的是用maven-assembly-plugin插件打包。
maven-assembly-plugin插件打包的教程网上已经有很多了,但是大部分都是在引用的包是在maven的repository里面的jar包,打包的时候引用包会包含在生成的jar文件里面。
可是如果引用的包是在本地呢?
最近在研究javaagent的时候,需要引用jdk提供的tools.jar,由于该jar包不在jre里面,所以必须额外引用:
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.6</version>
<scope>system</scope>
<systemPath>${JAVA_HOME}/lib/tools.jar</systemPath>
</dependency>
于是有了以下完整的pom
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.nathan.attach</groupId>
<artifactId>attach</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>attach</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.6</version>
<scope>system</scope>
<systemPath>${JAVA_HOME}/lib/tools.jar</systemPath>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.5</version>
<configuration>
<archive>
<manifest>
<mainClass>com.xxg.Main</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
接着试着跑一下
Administrator@WIN10-706021706 MINGW64 /j/eclipse-workspace/attach
$ mvn package assembly:single
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building attach 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ attach ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory J:\eclipse-workspace\attach\src\main\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ attach ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to J:\eclipse-workspace\attach\target\classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ attach ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory J:\eclipse-workspace\attach\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ attach ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to J:\eclipse-workspace\attach\target\test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ attach ---
[INFO] Surefire report directory: J:\eclipse-workspace\attach\target\surefire-reports
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.nathan.attach.attach.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.009 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ attach ---
[INFO] Building jar: J:\eclipse-workspace\attach\target\attach-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- maven-assembly-plugin:2.5.5:single (make-assembly) @ attach ---
[INFO] Building jar: J:\eclipse-workspace\attach\target\attach-0.0.1-SNAPSHOT-jar-with-dependencies.jar
[INFO]
[INFO] --- maven-assembly-plugin:2.5.5:single (default-cli) @ attach ---
[INFO] Building jar: J:\eclipse-workspace\attach\target\attach-0.0.1-SNAPSHOT-jar-with-dependencies.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 5.233 s
[INFO] Finished at: 2017-08-13T14:41:29+08:00
[INFO] Final Memory: 18M/363M
[INFO] ------------------------------------------------------------------------
Administrator@WIN10-706021706 MINGW64 /j/eclipse-workspace/attach
看起来正常?跑去target目录下看了以下,怎么肥四….只有几k??明显是没有把依赖包打进去…
这里有猫腻…
为什么打包的时候依赖包没有包含进去?我明明设置了jar-with-dependencies ,于是我开始怀疑是scope搞得怪,老规矩,先科普下scope里面的设置的意义:
按引用博文里面提到的:
system
从参与度来说,也provided相同,不过被依赖项不会从maven仓库抓,而是从本地文件系统拿,一定需要配合systemPath属性使用。
果然是scope搞的怪啊,那是不是我改成compile就行了呢?Nonono,由于引用本地jar包的特殊性,必须用system呢,不然会报错:
辗转反侧,斗转星移,穷尽我的爪牙,终于是找到一篇博文有提到这事情了:
里面提到用resource这个tag
<resources>
<resource>
<targetPath>lib/</targetPath>
<directory>lib/</directory>
<includes>
<include>**/my-jar.jar</include>
</includes>
</resource>
</resources>
于是我把jar包拷贝到项目的lib目录下
接着更该pom:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.nathan.attach</groupId>
<artifactId>attach</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>attach</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.6</version>
<scope>system</scope>
<systemPath>${JAVA_HOME}/lib/tools.jar</systemPath>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.5</version>
<configuration>
<archive>
<manifest>
<mainClass>com.nathan.attach.attach.AttachAPI</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<targetPath>lib/</targetPath>
<directory>lib/</directory>
<includes>
<include>**/tools.jar</include>
</includes>
</resource>
</resources>
</build>
</project>
接着生成jar:
Administrator@WIN10-706021706 MINGW64 /j/eclipse-workspace/attach
$ mvn package assembly:single
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building attach 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ attach ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource to lib/
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ attach ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ attach ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory J:\eclipse-workspace\attach\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ attach ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ attach ---
[INFO] Surefire report directory: J:\eclipse-workspace\attach\target\surefire-reports
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.nathan.attach.attach.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.011 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ attach ---
[INFO] Building jar: J:\eclipse-workspace\attach\target\attach-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- maven-assembly-plugin:2.5.5:single (make-assembly) @ attach ---
[INFO] Building jar: J:\eclipse-workspace\attach\target\attach-0.0.1-SNAPSHOT-jar-with-dependencies.jar
[INFO]
[INFO] --- maven-assembly-plugin:2.5.5:single (default-cli) @ attach ---
[INFO] Building jar: J:\eclipse-workspace\attach\target\attach-0.0.1-SNAPSHOT-jar-with-dependencies.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 7.537 s
[INFO] Finished at: 2017-08-13T15:16:48+08:00
[INFO] Final Memory: 13M/398M
[INFO] ------------------------------------------------------------------------
Administrator@WIN10-706021706 MINGW64 /j/eclipse-workspace/attach
看了下target目录,貌似正常?
于是我尝试跑一下,ops….还是失败了…为什么…
Administrator@WIN10-706021706 MINGW64 /j/eclipse-workspace/attach/target
$ java -jar attach-0.0.1-SNAPSHOT-jar-with-dependencies.jar 9504
Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/tools/attach/VirtualMachine
at com.nathan.attach.attach.AttachAPI.main(AttachAPI.java:21)
Administrator@WIN10-706021706 MINGW64 /j/eclipse-workspace/attach/target
我打开了生成的jar包的 MANIFEST.MF查看:
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: Administrator
Created-By: Apache Maven 3.5.0
Build-Jdk: 1.8.0_91
Main-Class: com.nathan.attach.attach.AttachAPI
不对啊..怎么没有引用信息…
实在没办法了,终于在*找到答案,教了我另外一种方法:
1.创建assembly.xml
<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>
指定
<dependencySet>
<outputDirectory>/</outputDirectory>
<unpack>true</unpack>
<scope>system</scope>
</dependencySet>
然后在pom那里引用
<descriptors> <descriptor>src/main/resource/assembly.xml</descriptor>
</descriptors>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.nathan.attach</groupId>
<artifactId>attach</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>attach</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.6</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/tools.jar</systemPath>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.5</version>
<configuration>
<archive>
<manifest>
<mainClass>com.nathan.attach.attach.AttachAPI</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<descriptors>
<descriptor>src/main/resource/assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
执行 mvn package assembly:single后
跑一下
J:\eclipse-workspace\attach\target>java -jar attach-0.0.1-SNAPSHOT-jar-with-all-dependencies.jar
java.util.ServiceConfigurationError: com.sun.tools.attach.spi.AttachProvider: Provider sun.tools.attach.WindowsAttachProvider could not be instantiated
com.sun.tools.attach.AttachNotSupportedException: no providers installed
at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:203)
at com.nathan.attach.attach.AttachAPI.main(AttachAPI.java:15)
Exception in thread "main" java.lang.NullPointerException
at com.nathan.attach.attach.AttachAPI.main(AttachAPI.java:21)
J:\eclipse-workspace\attach\target>
终于没有报找不到依赖类了!大功告成!!!这个报错是程序错误,本篇只讨论依赖包的引入。
脑袋空空,口袋空空,简单的一个打jar包,搞了一个下午,不容易啊!