springBoot 启动原理解析

java -jar 怎么启动SpringBoot??

我们打包SpringBoot 项目时,需要使用打包的插件,此时会在打包的jar 文件下, 存在 /META-INF/MANIFEST.MF 文件,来看下这个文件的内容;

Main-class: 是java -jar 命令真正调用的类

Start-Class: 是由自己编写的SpringBoot入口类

springBoot 启动原理解析_第1张图片

有没有小伙伴疑惑,这里为什么不直接使用 我们自己编写的入口呢?  我把main-class 改成我们自己编写的入口后,再启动会提示 找不到类的异常;

我们改回原方式,然后打断点看看SpringBoot是怎么处理的;

这里教大家调试的流程;  

1.使用插件打包我们的SpringBoot项目;下面是我的pom.xml



    4.0.0

    org.example
    springboot
    1.0-SNAPSHOT

    
        org.springframework.boot
        spring-boot-starter-parent
        2.4.5
    
    
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-loader
        

    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
                
                    
                        repackage
                    
                
            
        
    

2.idea工具配置jar application;

springBoot 启动原理解析_第2张图片

springBoot 启动原理解析_第3张图片

springBoot 启动原理解析_第4张图片

断点启动就可以调试了;

 

跟踪第一句 new JarLauncher(); 可以在其父类的构造参数中发现 this.archive = createArchive(); 内部的代码我没有一字一句的追,大体逻辑是 拿到我们运行的文件,判断是否为目录如果是目录 new ExplodedArchive(root) 如果不是 new JarFileArchive(root);

springBoot 启动原理解析_第5张图片

 

再往下跟lanuch()方法;发现创建了一个ClassLoader, 记得我们之前 直接启动自己编写的SpringBoot入口类时 提示类找不到; 当时的ClassLoader 为AppClassLoader, 默认加载ClassPath下的jar; 这里会不会是解决这个问题的呢? 我们主要追踪这部分代码; 跟进这个方法,查看一下构建ClassLoader时,传了哪些URL进去就可以了;

可以看到ClassLoader的类型是LaunchedURLClassLoader; 加载的是/BOOT-INF/classes 和 lib 下的文件;

springBoot 启动原理解析_第6张图片

springBoot 启动原理解析_第7张图片

我在自己编写的SpringBoot入口方法中,输出了当前的ClassLoader  我们观察一下,通过直接启动入口类 和 java -jar 启动输出的ClassLoader有什么不同;

1.通过IDEA 直接启动入口类,此时我的jar包 及 class文件都在ClassPath下;

springBoot 启动原理解析_第8张图片

2.通过java -jar命令启动; 可以发现两种启动方式 ClassLoader不同;


 

我们继续跟进 String launchClass = (jarMode != null && !jarMode.isEmpty()) ? JAR_MODE_LAUNCHER : getMainClass(); 获得入口类;

可以看到getMainClass 就是获取了MANIFEST.MF 文件中 Start-Class 的值;

springBoot 启动原理解析_第9张图片

最后通过反射调用,开始启动SpringBoot

 

SpringBoot 是怎么启动Spring容器的?

springBoot 启动原理解析_第10张图片

springBoot 启动原理解析_第11张图片

比较重要的几点:

1.根据当前的jar文件,判断是webmvc 或 webflux环境,启动不同的spring容器实例

2.加载META-INF/spring.factories 下的文件, 名字为 org.springframework.context.ApplicationContextInitializer 实现 ApplicationContextInitializer接口

3.加载META-INF/spring.factories 下的文件, 名字为 org.springframework.context.ApplicationListener 实现 ApplicationListener接口

springBoot 启动原理解析_第12张图片

1.创建SpringApplicationRunListeners 对象,整个SpringBoot生命周期使用事件进行管理; 默认实现类为EventPublishingRunListener; 我们可以通过 META-INF/spring.factories

   定义org.springframework.context.ApplicationListener=com.jtfu.boot.study.enchane.MyStartingListener 的方式来增强;

2.创建Spring容器, 根据前面解析的WebMCV 或者 WebFlux

3.初始化Spring容器参数,加载配置类

4.执行Spring容器的生命周期函数;

 

1.去 META-INF/spring.factories 查找名字为 org.springframework.boot.SpringApplicationRunListener 的实现类, Spring内置了一个. EventPublishingRunListener

springBoot 启动原理解析_第13张图片

EventPublishingRunListener 中的各个方法 会在SpringBoot 生命周期中被调用;

 

2.根据类型创建不同的Spring容器上下文

springBoot 启动原理解析_第14张图片

3.初始化Spring容器上下文的属性;  调用实现了ApplicationContextInitializer接口的方法, 发布contextPrepared事件,加载启动类,发布contextLoad事件

 

springBoot 启动原理解析_第15张图片

4.执行Spring容器的实例化函数,一路调用就会到了 Spring容器中最终的方法里面;  refresh();  这部分逻辑属于Spring源码;

springBoot 启动原理解析_第16张图片

5.发布started 事件

6.发布running 事件 完成Springboot 启动Spring容器上下文

 

内嵌tomcat是如何启动的?

经过前面分析可以知道Spring容器上下文的类型为 AnnotationConfigServletWebServerApplicationContext, 在执行Spring 的启动过程中 会调用 onRefresh()方法;

在这里完成了tomcat的启动 和 dispatchServlet ,Listener 的配置;

springBoot 启动原理解析_第17张图片

springBoot 启动原理解析_第18张图片

 

springBoot 启动原理解析_第19张图片

 

springBoot 启动原理解析_第20张图片

 

外部tomcat 是怎么启动SpringBoot项目的? (war包)

1.修改pom.xml 文件 打包方式改为war

springBoot 启动原理解析_第21张图片

2.排除web包下的内嵌tomcat

springBoot 启动原理解析_第22张图片

3.继承SpringBootServletInitializer,重写configure()方法;

springBoot 启动原理解析_第23张图片

4.打包完成后idea 启动tomcat 应用;

springBoot 启动原理解析_第24张图片

 

tomcat 启动时基于servlet 3.0规范,去META-INF/services ,查找文件 javax.servlet.ServletContainerInitializer  (这是个文件名,spi机制), 文件中有一个实现类,tomcat启动时就会调用它的 onStartup()方法;

能拿到我们自己实现接口的类,并调用它的onStartup()方法;

springBoot 启动原理解析_第25张图片

调用这个方法时,逻辑跟内嵌tomcat 启动 差不多,大家自行跟进理解一下吧.

你可能感兴趣的:(日常学习,源码,spring,tomcat,spring,boot)