在这篇博客里面我们将详细地讲解如何利用maven来创造一个fat jar
。可能大家对于fat jar
的概念还不是很熟悉,没关系,在开始进一步的讲解之前我会跟你说明fat jar
是什么的。另外本文的环境是
1 2 3 Maven 3.3 .9 JDK 1.8 Joda-Time 2.5
大家根据相应的情况自己创建一个Maven项目。
什么是Fat Jar? 什么是Fat Jar
?简单地说就是胖Jar
呗!哈哈!就是说这个Jar所装的东西比一般的Jar要多嘛!一般地,我们通过maven的插件maven-jar-plugin
所打包生成的jar都是只包含我们项目的源码的,它不包含我们所依赖的第三方库,这样就会导致一个问题,如果我们的第三方库不在CLASSPATH
下面会怎样?当然是会出现java.lang.NoClassDefFoundError
的问题咯!因此,我们需要使用一种方式,能使得项目所依赖的第三方库能够随着我们的项目源码一起被打包,这样我们就完全不用担心类找不到的问题啦!这就是Fat Jar
的来历!
创建Maven项目 两种方式:通过命令行或者通过IDE生成。
(1). 通过命令行:
1 2 $ mvn archetype:generate -DgroupId=com.qinjiangbo -DartifactId=FatJar -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
(2). 通过IDE生成,这里我用的IDEA
项目视图和主类
生成普通Jar 生成普通Jar我们可以使用maven-jar-plugin
这个插件来打包。Maven配置代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <build > <finalName > fat-jar-example</finalName > <plugins > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-jar-plugin</artifactId > <configuration > <archive > <manifest > <mainClass > com.qinjiangbo.App</mainClass > </manifest > </archive > </configuration > </plugin > </plugins > </build >
其中<mainClass>com.qinjiangbo.App</mainClass>
就是指明了main函数的所在地。我们生成好的jar名为fat-jar-example.jar
,在命令行打开项目的target
目录:
1 2 3 4 5 6 7 8 9 10 11 12 → jar tf fat-jar-example.jar META-INF/ META-INF/MANIFEST.MF com/ com/qinjiangbo/ com/qinjiangbo/App.class META-INF/maven/ META-INF/maven/com.qinjiangbo/ META-INF/maven/com.qinjiangbo/FatJar/ META-INF/maven/com.qinjiangbo/FatJar/pom.xml META-INF/maven/com.qinjiangbo/FatJar/pom.properties
很明显,这个jar包里面没有第三方库。我们来看看执行结果是什么?
1 2 3 4 5 6 7 8 9 10 11 → java -jar fat-jar-example.jar Hello Fat Jar! Exception in thread "main" java.lang.NoClassDefFoundError: org/joda/time/LocalDate at com.qinjiangbo.App.main(App.java:12) Caused by: java.lang.ClassNotFoundException: org.joda.time.LocalDate 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) ... 1 more
可以看到,这个Jar 正常地执行了一半,执行LocalDate.now()
的时候报错了,因为找不到LocalDate
这个类,很好理解了吧?好,我们再看看Fat Jar是什么样子的。
生成Fat Jar 生成Fat Jar我们使用的是One-Jar这个Maven插件。具体配置代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <build > <finalName > fat-jar-example</finalName > <plugins > <plugin > <groupId > com.jolira</groupId > <artifactId > onejar-maven-plugin</artifactId > <version > 1.4.4</version > <executions > <execution > <goals > <goal > one-jar</goal > </goals > </execution > </executions > </plugin > </plugins > </build >
通过mvn package
生成的Jar名称为fat-jar-example.one-jar.jar
。同样的,找到项目target
所在的目录:首先看看Fat Jar里面究竟是什么?
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 → jar -tf fat-jar-example.one-jar.jar META-INF/MANIFEST.MF main/fat-jar-example.jar lib/joda-time-2.5.jar com/ com/simontuffs/ com/simontuffs/onejar/ .version OneJar.class com/simontuffs/onejar/Boot$1 .class com/simontuffs/onejar/Boot$2 .class com/simontuffs/onejar/Boot$3 .class com/simontuffs/onejar/Boot.class com/simontuffs/onejar/Handler$1 .class com/simontuffs/onejar/Handler.class com/simontuffs/onejar/IProperties.class com/simontuffs/onejar/JarClassLoader$1 .class com/simontuffs/onejar/JarClassLoader$2 .class com/simontuffs/onejar/JarClassLoader$ByteCode .class com/simontuffs/onejar/JarClassLoader$FileURLFactory $1 .class com/simontuffs/onejar/JarClassLoader$FileURLFactory .class com/simontuffs/onejar/JarClassLoader$IURLFactory .class com/simontuffs/onejar/JarClassLoader$OneJarURLFactory .class com/simontuffs/onejar/JarClassLoader.class com/simontuffs/onejar/OneJarFile$1 .class com/simontuffs/onejar/OneJarFile$2 .class com/simontuffs/onejar/OneJarFile.class com/simontuffs/onejar/OneJarURLConnection.class src/ src/com/ src/com/simontuffs/ src/com/simontuffs/onejar/ src/OneJar.java src/com/simontuffs/onejar/Boot.java src/com/simontuffs/onejar/Handler.java src/com/simontuffs/onejar/IProperties.java src/com/simontuffs/onejar/JarClassLoader.java src/com/simontuffs/onejar/OneJarFile.java src/com/simontuffs/onejar/OneJarURLConnection.java doc/ doc/one-jar-license.txt
仔细和前面一个比较我们就可以很明显地看出区别,那就是包含了第三方库,同时也包含了onejar本身的源码。执行这个fat jar
看看会不会正常?
1 2 3 4 → java -jar fat-jar-example.one-jar.jar Hello Fat Jar! Current date: 2017-06-11
完全正常!!!说明是可行的!我推荐同学们如果需要使用Fat Jar
的时候就是用这种方式打包。
Fat Jar的应用 Fat Jar有哪些应用呢?一般来说,Fat Jar主要是有以下几个方向的应用:
做Java小工具应用程序,我们直接执行这个Jar就可以启动程序。
Spring-Boot生成的可执行Jar就是一种Fat Jar。
目前博主能够想到的方向就这两点哈,如果后面想到了继续补充!附上整个项目的Maven配置文件pom.xml
,大家可以直接拷贝,自己参照着修改一下再build就可以了!
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 <?xml version="1.0" encoding="UTF-8"?> <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.qinjiangbo</groupId > <artifactId > FatJar</artifactId > <version > 1.0-SNAPSHOT</version > <packaging > jar</packaging > <dependencies > <dependency > <groupId > joda-time</groupId > <artifactId > joda-time</artifactId > <version > 2.5</version > </dependency > </dependencies > <build > <finalName > fat-jar-example</finalName > <plugins > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-jar-plugin</artifactId > <configuration > <archive > <manifest > <mainClass > com.qinjiangbo.App</mainClass > </manifest > </archive > </configuration > </plugin > <plugin > <groupId > com.jolira</groupId > <artifactId > onejar-maven-plugin</artifactId > <version > 1.4.4</version > <executions > <execution > <goals > <goal > one-jar</goal > </goals > </execution > </executions > </plugin > </plugins > </build > </project >