FatJar 问题
什么是 FatJar
FatJar 又叫 uber-jar。uber 不是打车的 uber,而是德语里面的 uber,意思是英语里面的 over-勉强可以翻译为超越。
FatJar 是一个 all-in-one 的 jar,它可以让部署和运行更加便利,它让最终部署和运行的环境不依赖于任何 maven 或者 lib 的 classpath。
FarJar 的三种具体类型
非遮蔽的(Unshaded)
1 |
|
descriptorRef 有:
- bin 只打包编译结果,并包含 README, LICENSE 和 NOTICE 文件,输出文件格式为 tar.gz, tar.bz2 和 zip。
- jar-with-dependencies 打包编译结果,并带上所有的依赖,如果依赖的是 jar 包,jar 包会被解压开,平铺到最终的 uber-jar 里去。输出格式为 jar。
- src 打包源码文件。输出格式为 tar.gz, tar.bz2 和 zip。
- project 打包整个项目,除了部署输出目录 target 以外的所有文件和目录都会被打包。输出格式为 tar.gz, tar.bz2 和 zip。
所有的 jar 都被 unpack,然后 repack。
和 java 的缺省类加载器一起工作。
遮蔽的(Shaded)
1 |
|
所有的 jar 都被 unpack,然后 repack,而且被刻意 rename(所以叫 shade),以避免 dependency version clashes。这种 rename 会产生字节码级的变动,使得类的 package 变化。
和 java 的缺省类加载器一起工作。
shaded jar 依然有可能导致版本冲突,所以需要依赖 class-relocation 解决类重定位的问题,依赖 Resource Transformers 解决资源重定位的问题。
shaded jar 是为了解决这样的问题:
A 依赖 b/c,b/c依赖于 d 的两个版本。如果不产生 shaded,则 b 和 c 必有一段分支路径运行时失败。如果让 b 使用 shaded 过的 d,产生一个 shaded-b,则这个 shaded-b 本身包含引用了改名的 d,c 依赖于正常的 d,两段执行路径都可要正常运行完。
JAR of JARs
只是把 jar 打包在一起,jar 里有 jar。
我们常见的 maven package 无插件操作打出来的 jar 就是这种 jar。
默认的 fatjar 里不一定包含所有的依赖,所以需要使用插件:
1 |
|
其他 jar 的分类
- Skinny – Contains ONLY the bits you literally type into your code editor, and NOTHING else.
- Thin – Contains all of the above PLUS the app’s direct dependencies of your app (db drivers, utility libraries, etc).
- Hollow – The inverse of Thin – Contains only the bits needed to run your app but does NOT contain the app itself. Basically a pre-packaged “app server” to which you can later deploy your app, in the same style as traditional Java EE app servers, but with important differences.
- Fat/Uber – Contains the bit you literally write yourself PLUS the direct dependencies of your app PLUS the bits needed to run your app “on its own”.
Spring Boot 与 FatJar
实际上 Java 的原生类加载器处理普通的 Jar 里面的嵌套 class 是友好的,但处理嵌套的 jar 是不友好的。
Spring Boot 的 jar 就是 fatjar,这种 fatjar 携带所有依赖,而且有专有的类加载器来处理嵌套 jar 的依赖问题。这种 fatjar 是最简单的,运行起来最友好的。
分析依赖本来要逐层解压这种 jar-of-jars,但很多解析工具只解析一层的话,反而会被其他问题触发。例如,有时候为了解决依赖版本 冲突而指定 jar 的版本,而直接在一个多模块的 parent pom 里面短路地指定了一个依赖版本,反而会触发解析工具的检测规则。
1 |
|
这样会打印出两个 jar,一个 jar 是普通 jar,另一个 jar 是 jar.original。第二个 jar 是原始 jar,而第一个 jar 则是大而全的真正的 fat-jar。
参考文献: