java中常见jar包形式的联系和结构解析
一、背景
在学习使用maven来打包jar、或者使用springboot打包插件的时候,经常会看到jar、executable-jar、uberjar/fatjar、jar-with-dependencies、jar-in-jar/nested-jars等jar包形式,那么,这些jar包有之间联系吗?他们的结构有什么区别吗?
二、名词解释
pre:严格意义上讲,jar是一种打包压缩的文件格式,后缀是
.jar
,与.zip
是差不多的概念,本文所列举的几个jar包名,都是在java使用过程中出现的具有特定形式要求jar包。
1.jar
:
特指在java程序中可被用作依赖的jar包,java可以直接读取jar包中的class文件
参考:docs.oracle.com/javase/8/do…
2.executable-jar
:
当jar包被用来当作java直接启动“介质”的时候,不仅要求可以直接读取jar包中的class文件
,也要求提供程序入口的相关信息,这样jar包就成了executable-jar
参考:docs.oracle.com/javase/tuto…
3.uber-jar/fat-jar
:
这里需要区分开 应用程序的类,应用程序的依赖 两个概念,当一个jar包中不仅包含了应用程序本身的类,也包含了应用程序所需的依赖时,我们称之为fat-jar
、也叫uber-jar
4.jar-with-dependencies
:
特指maven打包插件maven-assembly-plugin
中的默认配置 jar-with-dependencies
,该插件配置打包时,会同时将业务代码及其依赖一同打包进最终jar包中
参考:maven.apache.org/plugins/mav…
5.jar-in-jar/nested-jars
:
jar-in-jar
貌似只有中文资料,官方名称应该是nested-jars
,意思就是jar包中包的jar包,特指springboot的打包插件spring-boot-maven-plugin
的打包结果,也会同时将业务代码及其依赖一同打包进最终jar包中
参考:maven.apache.org/plugins/mav…
PS:java程序默认是无法直接读取jar-in-jar中的依赖的
三、关系
一图胜千言:
四、jar包的结构
1.jar
:
将class文件
以特定形式组合打包,能够作为java程序的依赖,被java程序直接读取,它的结构如下:
PS:依赖jar包中的META-INF是可选的
2.executable-jar
:
java中定义的executable-jar
会在依赖jar包的基础上增加 /META-INF/MANIFEST.MF
文件,并在其中指定 Main-Class
属性,也就是指明程序的main入口
PS:
executable-jar
中的MANIFEST.MF
,除了Main-Class
外,其它属性是可选的
3.jar-with-dependencies
将依赖直接解压到jar下的顶级目录下:
4.jar-in-jar/nested-jars
将依赖以jar包的形式(不解压)直接放入到jar包中的/BOOT-INF.lib
目录下:
Q:既然maven已经提供了 jar-with-dependencies
,为什么springboot还要搞一个 jar-in-jar/nested-jars
呢?
springboot的文档里边有简要提到使用jar-in-jar/nested-jars
的原因,主要就是为了解决在依赖繁杂的情况下,全部解压到jar包根目录导致的类冲突和交叉覆盖,且难以溯源的问题。
五、启动过程
1.jar-with-dependencies
:
直接 java -jar xxx.jar
启动即可,跟普通的 executable-jar
一致,不需要进行额外处理。
2.jar-in-jar/nested-jars
:
也是 java -jar xxx.jar
进行启动,但是为了读取 nested-jar
的依赖,额外包装了一层,目的主要是扩展URL协议,并且使用了自定义的LaunchedURLClassLoader
ClassLoader
a.jar包结构信息:
可以看到Main-Class
并不是业务的main入口,而是springboot-loader的main入口:
b.实际的启动流程示意:
PS:
LaunchedURLClassLoader
一般也会被称作springboot classloader
,网上已有很多资料进行分析,这里不赘述。
转载自:https://juejin.cn/post/7065862239349112863