SprngBoot的启动流程

前言

最近,在学习Springboot + SpringCloud,以前就对传统的项目JSP + Servlet项目感兴趣,对哪些东西感兴趣呢?打个比方当客户端发出一个请求给服务器,在这个最始之初,他会先去校验Web.xml的配置,包括


<Servlet>,<Listener>以及<Context-param>等标签,

在研究的过程中出现了一些问题那就是Web.xml究竟是怎么样子解析的,就我目前的见解其实也能够猜出来一些,标签使我们所规定好的,因为上面有DOCTYPE约束,所以Tomcat必定会逐个解析这些标签,然后类似于Map集合的形式,将key所对应的Value存储到一个容器里面,这个容器可能是某种数据结构,当一个请求过来的时候,就会检索,可能说存在约束,毕竟web.xml中对于请求的限制有很多种,全拦截,不拦截,以及部分拦截。。。。巴拉巴拉,如果让我设计的话,我会去这么设计,奈何实力暂时不够,以及时间不充分,不能够去研究Tomcat的源码,在这里面在多说一句: 我感觉技术都是水到渠成的,就好比我现在研究ActiveMQ我接触这个项目也快一年了,一开始是写传统项目的CRM,OA以及一些财务系统,就是一个公司内部使用,用不到这些中间件,当我的基础好了,并且找对正确的方法,一切都是那么水到渠成,理论加实践两手抓,才会好些,不要茫然的去追求一些新技术!没有意义的,基础足够夯实,一切都是那么水到渠成,扯得有点远了,下面我们还是开始说Springboot的启动流程吧!

先从项目的架构开始说

  • 1.如何将项目打包

这是一个Springboot项目,我们先不对他做任何的操作(不排除它自身所内置的Tomcat),那么当我们想要独立于编译器取运行这个项目的时候,可能我们需需要将他打成一个BootJar这样子一个Jar包

Ps:这是一个Gradle项目,过几天我把Gradle项目的创建流程写一个文档,记录一下,还是跟传统的项目有很大却别的

  • 2.打包输出的信息以及输出的BootJar包位置

  • 3.bootJar的结构

上面的目录结构是我们将Spring-lecture.jar给解压之后所展现的目录结构,下面我们就重点说一下他们三个的区别

  • 目录结构分析

    • b.BOOT-INF这个文件夹点进去会发现一个问题,存在两个文件夹1. classes文件夹 2. lib文件夹其中classes这文件夹里面的目录结构跟我们的类路径是一个样子的并且其中包括配置文件,lib这个文件夹里面存放的是我们当前项目所依赖的Jar包

    • a.MANIFEST.MF,这个文件我们用记事本的形式打开会发现如下的结构

      • (1) Manifest-Version: 1.0表示了当前项目的版本号
      • (2) Start-Class: com.shengsiyuan.boot.MyApplication可能说我们存在一些问题,但是我们知道MyApplication这个代表了我们Springboot项目启动类的名称,我们可能认为项目一开始启动的时候是先启动MyApplication这个类,因为里面包含了一个Main函数对吧!!!这里面我们先做一个小标记,后续我们再来解决这个问题
      • (3) Main-Class: org.springframework.boot.loader.JarLauncher这里面给了一个我们类似于我们所引用Jar包的一个类org.springframework.boot.loader.JarLauncher,这个类也存在很大的疑问,为什么Springboot项目会给出这么一个东西???最起码,一开始是让我感觉很奇怪的!,我们先把这些个疑问点都放在这里,随着问题的讲解,问题都会慢慢解决掉
    • c.org这个文件夹,当我们一层一层点进去的时候会发现一个问题,我们上面所提到的org.springframework.boot.loader.JarLauncher他的.class文件是存在于这个文件件下面的,那么是不是说,上面之间是否存在着某一种关联关系呢?我们也先把这个疑问放在这里,继续向下.

传统项目的打包方式

我们在传统的项目当中一般都是将项目打成war包,然后丢在Tomcat的webapp目录下面,这个项目会随着Tomcat的启动而启动,说道这里就不得不提一个问题,war包的目录结构如下:

就是我们在一开始的时候编译文件的时候他也存在类似于Springboot里面的文件,

  • 1.META-INF里面存放着一个MANIFEST.MF文件,暂时可以把它当成一个配置文件,具体的细节,稍后再次进行讲解,相信说完之后你会对这个文件有一个大体的了解
  • 2.WEB-INF这个东西想必大家不会陌生,一般在我们的项目路径中,wap-app下面就会存在WEB-INF这个文件夹,当我们点进去的时候会发现也存在类似于bootJar的文件结构,classes里面存放了我们当前项目编译后的文件,lib存放了当前项目所依赖的Jar包,乍一看跟bootJar貌似没有什么本质上面的区别!

META-INF参数详解(我们只说,我们用到过的)

  • 1.Main-Class 定义jar文件的入口类,该类必须是一个可执行的类,一旦定义了该属性即可通过 java -jar x.jar来运行该jar文件。极其重要,给我打上重点
  • 2.Manifest-Version用来定义manifest文件的版本,例如:Manifest-Version: 1.0,了解就好
  • 3.Start-Class:就是我们自己写的main函数

Jar与War的区别

Jar在以前我们应用的时候,一般都是项目依赖于一个公共包,打个比方关于时间类型处理的方法,关于字符串类型的处理方法,为了可移植性,我们完全可以将这些常用的方法,打包成一个Jar包,以方便下次继续用.

War这个比较好理解,当我们做好一个Web应用的时候,通常你想要发布的时候,会将他打成War包丢在Tomcat容器下面的Webapps目录下面,当启动Tomcat的时候,这个War包会自己进行解压缩,就相当于发布了

上面的知识可能大家都比较了解,这个也不是我所要说的,就当下2019年5月28日这个年代看来,Jar包与War包最根本的差别在于Jar包可以直接利用java -jar xxxx.jar****这个指令来启动一个项目,而你War!不行,最根本的原因在于"Springboot"里面内置了Tomcat(由于我们再导入依赖的时候,会自动导入Tomcat,你也可以自己将Tomcat的依赖剥离出去)。。。

Springboot 启动项目的方式

SpringBoot我们采用的是java -jar xxx.jar这种方式来启动的,那么就会有以下疑问

  • 1.他是如何启动一个项目的
    • 由于bootJar里面的构造和传统的War包是不一样的,因为boorJar需要作为一个自启动项目,那么由于bootJar的独立结构,加载不到BOOT-INF文件夹下面的lib里面的jar包,我们可能猜测得到之所以Tomcat能记载war包里面的lib依赖jar包,那么一定是Tomcat进行了解析,那么既然bootJar不能像War包一样的结构那么我们是不是可以自己去想办法解决这个问题呢?因为,Jar包说白了也是由类以及一些规则组成的!上面我们已经知道了一个Springboot项目的Main-Class是:org.springframework.boot.loader.JarLauncher下面我们去看下源码

  • 1.首先我们来说一下第一点,Launcher是什么?是一个基于Jar的可归档文件,这个Launcher启动器被假定为包含BOOT-INF/lib文件夹并且包含应用类文件目录BOOT/INT/classes/

  • 2.这个第二点是不是和我们说过的bootJar文件的目录结构特别相似,而且完全不同于War包?

  • 3.这个一个main方法,他是由JVM首要加载,可以当做入口,记住这么一句话**“Springboot项目首先运行的是JarLauncher这个.class文件里面的main方法”**

  • 4.我们我们这样子理解,我们在上面所说的,我们需要自己去自定义类加载器,那么类加载器在加载jar包和class文件的时候是不相同的,先这样子去理解,下面还会讲解.
    继续点击下去,进入第二层代码

  • 1.这是一个基础的类,能够启动一个应用,什么样子的一个应用呢?被一个或者更多个Archive文件完全路径配置的

  • 2.启动这个应用,这个方法是一个初始化的切入点应该被一个拥有main方法的子类所调用

  • 3.我们来看比较重要的ClassLoader classLoader = createClassLoader(getClassPathArchives());,创建一个类加载器,在上面我们已经说过了,由于bootJar的目录结构不同于War所以可能不能根据Tomcat的默认规则去加载依赖Jar包,那么如果你想要去加载就需要自定义一个类加载器,去加载我们Boot-INF下面的文件夹,之后我们点进getClassPathArchives()这个方法什么意思呢返回将用于构造类路径的归档。一直点进去发现他又跳回了JarLauncher这个类文件中,说白了这个方法就是看一看类文件或者Jar文件,有没有必要添加到**ClassPath(一般在本地配置环境都需要配置,类加载器系统类加载器会从这个里面进行加载)**下面

  • 4.下面的方法launch(args, getMainClass(), classLoader);,里面的getMainClass()寻找了Start-Class这个配置,之后就是我们以前所认为的,展现给别人面前的main()开始运行了

以上就是我对Springboot启动流程的理解,难免会有所疏漏,如有发现,请指出,谢谢。

发布了32 篇原创文章 · 获赞 26 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_27416233/article/details/90640046