jar-with-dependencies
3. 嵌套方法(Jar of Jars)
还是一种办法就是在 jar 包里嵌套其他 jar,这个方法可以彻底避免解压同名覆盖的问题,但是这个方法不被 JVM 原生支持,因为 JDK 提供的 ClassLoader 仅支持装载嵌套 jar 包的 class 文件。所以这种方法需要自定义 ClassLoader 以支持嵌套 jar。
Onejar Maven Plugin
One-JAR 就是一个基于上面嵌套 jar 实现的工具。onejar-maven-plugin 是社区基于 onejar 实现的 maven 插件。
com.jolira
onejar-maven-plugin
1.4.4
one-jar
Spring boot plugin
One-JAR 有点年久失修,好久没有维护了,Spring Boot 提供的 Maven Plugin 也可以打包 Fatjar,支持非遮蔽和嵌套的混合模式,并且支持 maven 和 gradle 。
org.springframework.boot
spring-boot-maven-plugin
ZIP
org.jruby
jruby-complete
plugins {
id 'org.springframework.boot' version '2.0.4.RELEASE'
}
bootJar {
requiresUnpack '**/jruby-complete-*.jar'
}
requiresUnpack 参数可以定制那些 jar 不希望被解压,采用嵌套的方式打包到 Fatjar 内部。
其打包后的内部结构为
example.jar
|
+-META-INF
| +-MANIFEST.MF
+-org
| +-springframework
| +-boot
| +-loader
| +-
+-BOOT-INF
+-classes
| +-mycompany
| +-project
| +-YourClasses.class
+-lib
+-dependency1.jar
+-dependency2.jar
应用的类文件被放置到 BOOT-INF/classes 目录,依赖包被放置到 BOOT-INF/lib 目录。
查看 META-INF/MANIFEST.MF 文件,其内容为
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.mycompany.project.MyApplication
启动类是固定的 org.springframework.boot.loader.JarLauncher,应用程序的入口类需要配置成 Start-Class。这样做的目的主要是为了支持嵌套 jar 包的类装载,替换掉默认的 ClassLoader。
但是函数计算 Java Runtime 需要的 jar 包是一种打包结构,在服务端运行时会解压开,./lib 目录加到 classpath 中,单不会调用 Main-Class。所以自定义 ClassLoader 是不生效的,所以不要使用嵌套 jar 结构,除非在入口函数指定重新定义 ClassLoader 或者 classpath 以支持 BOOT-INF/classes 和 BOOT-INF/lib 这样的定制化的类路径。
小结
单从 Fatjar 的角度看, Spring boot maven/gradle 做得最精致。但是 jar 包内部的自定义路径解压开以后和函数计算是不兼容的。所以如果用于函数计算打包,建议使用 Unshaded 或者 Shared 的打包方式,但是需要自己注意文件覆盖问题。
写在最后:欢迎留言讨论,私信“Java”或“架构资料”有惊喜哟!加关注,持续更新!!!
閱讀更多 Java互聯網架構師 的文章