我准备战斗到最后,不是因为我勇敢,是我想见证一切。 --双雪涛《猎人》
文章目录
Thinking
- 一个技术,为什么要用它,解决了那些问题?
- 如果不用会怎么样,有没有其它的解决方法?
- 对比其它的解决方案,为什么最终选择了这种,都有何利弊?
- 你觉得项目中还有那些地方可以用到,如果用了会带来那些问题?
- 这些问题你又如何去解决的呢?
声明:本文基于springboot 2.1.3.RELEASE
正文的第一个疑问就是:
- springboot 为什么可以直接使用jar 运行?
- 那么jar包的内部解构是怎么样的?
- springboot 的启动过程又是怎么样的?
这里首先声明在java的归档文件中(jar)的规定:
在一个jar文件当中,我们必须要将指定为
Main-Class
的那个类作为顶层的jar文件(就是该启动类的jar文件必须放置在整个解压目录或者jar文件内部的顶层目录下),意思就是,执行的Main-Class
是不允许被嵌套的。 对于一个
Jar
文件来说,被指定为入口类Main-Class
的一个具体类,那么这个类连同他的包结构,一定是位于这个Jar
文件的顶层目录,而不能再位于其他的子目录中。
- 以上两种说法,强调了SpringBoot就存在了问题,在一个打包完jar文件后,只能允许一个
Main-Class
入口类,可是我们自己写的启动类是根本不具备启动整个项目的实力的,那么SpringBoot
是怎么完美的避开这种协议,实现jar包中嵌套用户启动类,并且可以完美随处运行的呢?
1、SpringBoot jar包的内部结构
将打包好的Jar包,使用命令解压出来
- 存放的是 配置文件和编写的字节码文件
- 存放的是自动生成的一些配置信息(类似于:maven配置,jdk环境、os环境等) you should not put anything into META-INF yourself. Instead
- 存放的是真正的springboot 的启动文件的字节码文件
- 大致可以看到在该启动类下的路径,尝试使用该路径引入jar依赖
<!--引入 springboot 启动依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-loader</artifactId>
</dependency>
引入该jar后,可以简单的发现,该jar包的所有路径都是跟解压出来的jar的loader路径下的内容相同的。
不难发现了,speingboot正是使用的spring-boot-loader
这个jar来完成springboot 的整个启动加载动作的。
在源码面前,所有的花哨都是扯淡的😄,来🐱一眼里面最显眼的JarLauncher
类。
是不是一眼就感觉到亲切无比了哈?😄
这里声明一点,我们引入的
spring-boot-loader
是不会影响springboot 的启动的。但是会在加载的lib目录下生成jar文件,我们重新打包一次,🐱一眼。
其他目录并没有什么改变。
至此,大概的了解了,springboot 打包为jar后的整个目录样子。
下面,探讨一下这种路径的优点,或者说为什么是这样的结构
2、SpringBoot-启动原理
2.1、为什么SpringBoot打包的jar可以直接运行
当执行
java -jar spring_lecture-0.0.1.jar
命令时,整个jar的入口是什么?
在上面简单的查看了一下整个jar包的目录结构,在Java运行jar时,是根据MATA-INF
中的.MF
文件,寻找到Main-Class
指定的全限定名进行加载的。
<jar ...>
<manifest>
<attribute name="Main-Class" value="MyApplication"/>
</manifest>
</jar>
所以,在jar文件中,MATA-INF
中的.MF
文件定义了启动类