平时项目大多用到的是war包,今天实现了一个简单功能,无需部署到web服务器上,只需本地跑java代码即可,因此只要生成一个jar包。那么怎么让maven项目打成一个可以使用java命令跑的jar包呢?这里通过maven插件实现:
首先修改pom.xml文件,这里需要新增build节点,在build里加入plugins节点:
<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.wlf.net</groupId>
<artifactId>point-circle</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>point-circle</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.12.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>com.vividsolutions</groupId>
<artifactId>jts</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc14</artifactId>
<version>10.2.0.2.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.wlf.net.point.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>
${project.build.directory}/lib
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
上面的pom文件里有两个plugin,第一个是在jar包中的META-INF/MANIFEST.MF中指定Main-Class,指定lib库的jar包依赖classpath;第二个是把依赖到的lib库jar包都复制到配置的classpathPrefix目录下,这一步不做的话运行打出来的jar包会报错,因为相关依赖的jar包虽然配置了classpath但其实该classpath下并没有真实的jar包存在。addClasspath为true说明需要在MANIFEST.MF加上classpath并配置依赖包,classpathPrefix指定依赖包所在的目录,mainClass指定MANIFEST.MF中的Main-Class。${project.build.directory}这变量是maven内置的,系统会自动寻找,其实就编译class的目录target,这里配置的${project.build.directory}/lib,在我本机就是E:\workspace\point-circle\target\lib。每次修改完pom配置文件之后,记得在Eclipse右击项目,点击Update Project让修改生效。
执行maven打包命令:
E:\workspace\point-circle>mvn clean install
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building point-circle 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ point-circle ---
[INFO] Deleting E:\workspace\point-circle\target
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ point-circle ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory E:\workspace\point-circle\src\main\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ point-circle ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 3 source files to E:\workspace\point-circle\target\classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ point-circle ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory E:\workspace\point-circle\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ point-circle ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to E:\workspace\point-circle\target\test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ point-circle ---
[INFO] Surefire report directory: E:\workspace\point-circle\target\surefire-reports
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.wlf.net.point.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.063 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ point-circle ---
[INFO] Building jar: E:\workspace\point-circle\target\point-circle-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- maven-dependency-plugin:2.8:copy-dependencies (copy) @ point-circle ---
[INFO] Copying commons-dbcp-1.2.2.jar to E:\workspace\point-circle\target\lib\commons-dbcp-1.2.2.jar
[INFO] Copying spring-expression-4.3.12.RELEASE.jar to E:\workspace\point-circle\target\lib\spring-expression-4.3.12.RELEASE.jar
[INFO] Copying jts-1.8.jar to E:\workspace\point-circle\target\lib\jts-1.8.jar
[INFO] Copying commons-pool-1.3.jar to E:\workspace\point-circle\target\lib\commons-pool-1.3.jar
[INFO] Copying hamcrest-core-1.3.jar to E:\workspace\point-circle\target\lib\hamcrest-core-1.3.jar
[INFO] Copying spring-aop-4.3.12.RELEASE.jar to E:\workspace\point-circle\target\lib\spring-aop-4.3.12.RELEASE.jar
[INFO] Copying spring-web-4.3.12.RELEASE.jar to E:\workspace\point-circle\target\lib\spring-web-4.3.12.RELEASE.jar
[INFO] Copying junit-4.12.jar to E:\workspace\point-circle\target\lib\junit-4.12.jar
[INFO] Copying commons-logging-1.2.jar to E:\workspace\point-circle\target\lib\commons-logging-1.2.jar
[INFO] Copying spring-jdbc-4.3.12.RELEASE.jar to E:\workspace\point-circle\target\lib\spring-jdbc-4.3.12.RELEASE.jar
[INFO] Copying spring-webmvc-4.3.12.RELEASE.jar to E:\workspace\point-circle\target\lib\spring-webmvc-4.3.12.RELEASE.jar
[INFO] Copying spring-core-4.3.12.RELEASE.jar to E:\workspace\point-circle\target\lib\spring-core-4.3.12.RELEASE.jar
[INFO] Copying spring-context-4.3.12.RELEASE.jar to E:\workspace\point-circle\target\lib\spring-context-4.3.12.RELEASE.jar
[INFO] Copying ojdbc14-10.2.0.2.0.jar to E:\workspace\point-circle\target\lib\ojdbc14-10.2.0.2.0.jar
[INFO] Copying spring-beans-4.3.12.RELEASE.jar to E:\workspace\point-circle\target\lib\spring-beans-4.3.12.RELEASE.jar
[INFO] Copying spring-context-support-4.3.12.RELEASE.jar to E:\workspace\point-circle\target\lib\spring-context-support-4.3.12.RELEASE.jar
[INFO] Copying spring-tx-4.3.12.RELEASE.jar to E:\workspace\point-circle\target\lib\spring-tx-4.3.12.RELEASE.jar
[INFO]
[INFO] --- maven-install-plugin:2.4:install (default-install) @ point-circle ---
[INFO] Installing E:\workspace\point-circle\target\point-circle-0.0.1-SNAPSHOT.jar to E:\Users\wulf\.m2\repository\com\wlf\net\point-circle\0.0.1-SNAPSHOT\point-circle-0.0.1-SNAPSHOT.jar
[INFO] Installing E:\workspace\point-circle\pom.xml to E:\Users\wulf\.m2\repository\com\wlf\net\point-circle\0.0.1-SNAPSHOT\point-circle-0.0.1-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 17.180 s
[INFO] Finished at: 2018-01-25T21:13:38+08:00
[INFO] Final Memory: 23M/196M
[INFO] ------------------------------------------------------------------------
看下我们打出来的jar包里的MANIFEST.MF目录和内容:point-circle-0.0.1-SNAPSHOT.jar\META-INF\MANIFEST.MF
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: wulf
Class-Path: lib/spring-core-4.3.12.RELEASE.jar lib/commons-logging-1.2
.jar lib/spring-context-support-4.3.12.RELEASE.jar lib/spring-beans-4
.3.12.RELEASE.jar lib/spring-context-4.3.12.RELEASE.jar lib/spring-ao
p-4.3.12.RELEASE.jar lib/spring-expression-4.3.12.RELEASE.jar lib/spr
ing-web-4.3.12.RELEASE.jar lib/spring-webmvc-4.3.12.RELEASE.jar lib/s
pring-jdbc-4.3.12.RELEASE.jar lib/spring-tx-4.3.12.RELEASE.jar lib/jt
s-1.8.jar lib/commons-dbcp-1.2.2.jar lib/commons-pool-1.3.jar lib/ojd
bc14-10.2.0.2.0.jar
Created-By: Apache Maven 3.3.9
Build-Jdk: 1.8.0_102
Main-Class: com.wlf.net.point.App
上面列出了classpath里所依赖到的jar包列表、主class。最后打开命令行界面执行jar包:
E:\>cd E:\workspace\point-circle\target
E:\workspace\point-circle\target>java -jar point-circle-0.0.1-SNAPSHOT.jar
Exception in thread "main" java.lang.NullPointerException
at com.wlf.net.point.App.main(App.java:39)
空指针是spring的注入问题,这里说明可执行jar包出炉了。但如果我把这个新鲜烤出来的jar包复制到另一个地方,比如E盘,再执行就报找不到依赖的jar包了:
E:\>java -jar point-circle-0.0.1-SNAPSHOT.jar
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: com/vividsolutions/jts/io/ParseException
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
at java.lang.Class.getMethod0(Class.java:3018)
at java.lang.Class.getMethod(Class.java:1784)
at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)
Caused by: java.lang.ClassNotFoundException: com.vividsolutions.jts.io.ParseException
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 7 more
看来这个面包只能在面包店里吃了,我打包带走就吃不了。这是因为classpath已经设定了依赖jar包的位置了,只能到当前目录target的lib目录下找,你拿到其他地方还想跑也可以,那么请你一并把lib目录复制过去吧。难道我吃个面包还得随身带个烤面包机吗?是的,但是我们不用到处复制,把烤面包机放进面包里就可以了。这里我们就要用到另一个maven插件了,它可以把我们所依赖的jar包一并打入我们自己的jar包里。我们干掉之前那两个plugin,换成maven-assembly-plugin这个plugin,改后的pom文件的build节点如下:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.wlf.net.point.App</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
再次执行打包命令:
E:\workspace\point-circle>mvn clean install
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building point-circle 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ point-circle ---
[INFO] Deleting E:\workspace\point-circle\target
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ point-circle ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory E:\workspace\point-circle\src\main\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ point-circle ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 3 source files to E:\workspace\point-circle\target\classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ point-circle ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory E:\workspace\point-circle\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ point-circle ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to E:\workspace\point-circle\target\test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ point-circle ---
[INFO] Surefire report directory: E:\workspace\point-circle\target\surefire-reports
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.wlf.net.point.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.068 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ point-circle ---
[INFO] Building jar: E:\workspace\point-circle\target\point-circle-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- maven-assembly-plugin:2.2-beta-5:single (make-assembly) @ point-circle ---
[INFO]
[INFO] --- maven-install-plugin:2.4:install (default-install) @ point-circle ---
[INFO] Installing E:\workspace\point-circle\target\point-circle-0.0.1-SNAPSHOT.jar to E:\Users\wulf\.m2\repository\com\wlf\net\point-circle\0.0.1-SNAPSHOT\point-circle-0.0.1-SNAPSHOT.jar
[INFO] Installing E:\workspace\point-circle\pom.xml to E:\Users\wulf\.m2\repository\com\wlf\net\point-circle\0.0.1-SNAPSHOT\point-circle-0.0.1-SNAPSHOT.pom
[INFO] Installing E:\workspace\point-circle\target\point-circle-0.0.1-SNAPSHOT-jar-with-dependencies.jar to E:\Users\wulf\.m2\repository\com\wlf\net\point-circle\0.0.1-SNAPSHOT\point-circle-0.0.1-SNAPSHOT-jar-with-dependencies.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 24.621 s
[INFO] Finished at: 2018-01-26T11:17:05+08:00
[INFO] Final Memory: 29M/230M
[INFO] ------------------------------------------------------------------------
这次生成的jar包里多了很多东西,而且名称也变了:point-circle-0.0.1-SNAPSHOT-jar-with-dependencies.jar。我们把它复制到E盘执行,这次没问题了:
C:\Users\wulf>e:
E:\>java -jar point-circle-0.0.1-SNAPSHOT-jar-with-dependencies.jar
Exception in thread "main" java.lang.NullPointerException
at com.wlf.net.point.App.main(App.java:39)
还可以用另外一个插件maven-shade-plugin来代替maven-assembly-plugin,修改后的pom文件如下:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.wlf.net.point.App</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
执行maven打包:
:\workspace\point-circle>mvn clean install
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building point-circle 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ point-circle ---
[INFO] Deleting E:\workspace\point-circle\target
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ point-circle ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 2 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ point-circle ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 3 source files to E:\workspace\point-circle\target\classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ point-circle ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory E:\workspace\point-circle\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ point-circle ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to E:\workspace\point-circle\target\test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ point-circle ---
[INFO] Surefire report directory: E:\workspace\point-circle\target\surefire-reports
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.wlf.net.point.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.036 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ point-circle ---
[INFO] Building jar: E:\workspace\point-circle\target\point-circle-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- maven-shade-plugin:2.4.1:shade (default) @ point-circle ---
[INFO] Including org.springframework:spring-core:jar:4.3.12.RELEASE in the shaded jar.
[INFO] Including commons-logging:commons-logging:jar:1.2 in the shaded jar.
[INFO] Including org.springframework:spring-context-support:jar:4.3.12.RELEASE in the shaded jar.
[INFO] Including org.springframework:spring-beans:jar:4.3.12.RELEASE in the shaded jar.
[INFO] Including org.springframework:spring-context:jar:4.3.12.RELEASE in the shaded jar.
[INFO] Including org.springframework:spring-aop:jar:4.3.12.RELEASE in the shaded jar.
[INFO] Including org.springframework:spring-expression:jar:4.3.12.RELEASE in the shaded jar.
[INFO] Including org.springframework:spring-web:jar:4.3.12.RELEASE in the shaded jar.
[INFO] Including org.springframework:spring-webmvc:jar:4.3.12.RELEASE in the shaded jar.
[INFO] Including org.springframework:spring-jdbc:jar:4.3.12.RELEASE in the shaded jar.
[INFO] Including org.springframework:spring-tx:jar:4.3.12.RELEASE in the shaded jar.
[INFO] Including com.vividsolutions:jts:jar:1.8 in the shaded jar.
[INFO] Including commons-dbcp:commons-dbcp:jar:1.2.2 in the shaded jar.
[INFO] Including commons-pool:commons-pool:jar:1.3 in the shaded jar.
[INFO] Including com.oracle:ojdbc14:jar:10.2.0.2.0 in the shaded jar.
[INFO] Replacing original artifact with shaded artifact.
[INFO] Replacing E:\workspace\point-circle\target\point-circle-0.0.1-SNAPSHOT.jar with E:\workspace\point-circle\target\point-circle-0.0.1-SNAPSHOT-shaded.jar
[INFO] Dependency-reduced POM written at: E:\workspace\point-circle\dependency-reduced-pom.xml
[INFO] Dependency-reduced POM written at: E:\workspace\point-circle\dependency-reduced-pom.xml
[INFO]
[INFO] --- maven-install-plugin:2.4:install (default-install) @ point-circle ---
[INFO] Installing E:\workspace\point-circle\target\point-circle-0.0.1-SNAPSHOT.jar to E:\Users\wulf\.m2\repository\com\wlf\net\point-circle\0.0.1-SNAPSHOT\point-circle-0.0.1-SNAPSHOT.jar
[INFO] Installing E:\workspace\point-circle\dependency-reduced-pom.xml to E:\Users\wulf\.m2\repository\com\wlf\net\point-circle\0.0.1-SNAPSHOT\point-circle-0.0.1-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.557 s
[INFO] Finished at: 2018-01-26T16:33:45+08:00
[INFO] Final Memory: 28M/195M
[INFO] ------------------------------------------------------------------------
注意这里会生成两个jar,一个带original前缀表示原始jar包,一个没带该前缀,我们要用的是没带的。