springBoot 启动原理解析

java -jar 怎么启动SpringBoot??

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

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

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

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

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

这里教大家调试的流程;  

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

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>springboot</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.5</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-loader</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals><goal>repackage</goal></goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

2.idea工具配置jar application;

断点启动就可以调试了;

 

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

 

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

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

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

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

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


 

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

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

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

 

SpringBoot 是怎么启动Spring容器的?

比较重要的几点:

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接口

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

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

 

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

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

 

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

5.发布started 事件

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

 

内嵌tomcat是如何启动的?

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

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

 

 

 

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

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

2.排除web包下的内嵌tomcat

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

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

 

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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值