SpringBoot源码学习一——run的启动流程

一、SpringBoot

SpringBoot是Spring下的子项目,它是Spring组件集成的一站式解决方案。采用约定优于配置的思想简化了繁重的配置,提供了各种启动器,大大降低使用Spring的难度,使开发者能快速上手。
详细的关于SpringBoot的介绍,请看这篇文章SpringBoot是什么

二、启动流程

2.1 环境准备

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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
  <!--
pom文件一个重要的属性就是packaging(打包类型),一般来说所有的父级项目的packaging都为pom,packaging默认类型jar类型
  <packaging>pom</packaging>
  -->

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.spring.study</groupId>
    <artifactId>jdknew</artifactId>
    <version>1.0.0-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <argLine>-Dfile.encoding=UTF-8</argLine>
        <spring-cloud.version>Hoxton.SR3</spring-cloud.version>
    </properties>


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <!--            <scope>test</scope>-->
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>


        <!-- <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-config</artifactId>
         </dependency>-->

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

JdkApplication

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class JdkApplication {
    public static void main(String[] args) {
        SpringApplication.run(JdkApplication.class, args);
    }
}

2.2 SpringBoot启动流程

先找到SpringBoot启动的入口

SpringApplication.run(JdkApplication.class, args);–> run(new Class<?>[] { primarySource }, args);–>new SpringApplication(primarySources).run(args);

2.2.1 SpringApplication构造方法

SpringApplication(primarySources)–>this(null, primarySources);
在这里插入图片描述
deduceFromClasspath用于推断当前环境是否为web环境,详细分析

setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));设置监听器,这些监听器主要监听容器生命周期的各个阶段。getSpringFactoriesInstances(Class type)读取的就是META-INF/spring.factories里面配置的对应Class的实现类

2.2.2 run(args)

在这里插入图片描述

注释:启动应用,创建或刷新一个新的上下文(即容器)

  • ConfigurableApplicationContext这个容器提供了配置应用程序上下文的工具,这里封装了配置方法和容器的生命周期方法。
  • SpringApplicationRunListeners是一个执行监听的集合,SpringApplicationRunListener有一些方法,在SpringApplication启动的各个阶段会调用这些方法。SpringApplicationRunListener的子类EventPublishingRunListener实现了这些生命周期方法,发布相应的事件。
2.2.2.1 listeners.starting();

listeners.starting();–>listener.starting();
在这里插入图片描述
使用事件发布器发布一个ApplicationStartingEvent事件,setListeners设置的监听器监听到这里发布的事件,就会执行监听器的onApplicationEvent方法
在这里插入图片描述
例如LoggingApplicationListener用来配置容器使用的日志系统

2.2.2.2 createApplicationContext

回到run方法
在这里插入图片描述
createApplicationContext();前面几行是读取application.yml的配置做一些处理,进入createApplicationContext
在这里插入图片描述
创建名为AnnotationConfigServletWebServerApplicationContext的容器,从名字可以看出它支持注解配置,可以从configuration文件中获取bean,支持启动Servlet容器(tomcat、jetty),提供web服务。
再最后一行也很重要在这里插入图片描述

BeanUtils.instantiateClass(contextClass);–>instantiateClass(clazz.getDeclaredConstructor());–>ctor.newInstance(argsWithDefaultValues);

在这里插入图片描述
ctor.newInstance就是利用反射调用ctor的构造方法产生一个实例。进入就到了AnnotationConfigServletWebServerApplicationContext的无参构造方法
在这里插入图片描述

new AnnotatedBeanDefinitionReader(this);–>this(registry, getOrCreateEnvironment(registry));–>AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);–>registerAnnotationConfigProcessors(registry, null);

在这里插入图片描述
在这块拿到ConfigurationClassPostProcessor的BeanDefinition,添加到了registry。之后在invokeBeanFactoryPostProcessors里面调用getBean就完成了ConfigurationClassPostProcessor的实例化和初始化。SpringBoot的自动装配就是在后置增强器ConfigurationClassPostProcessor完成的

2.2.2.3 prepareContext()

在调用容器的构造方法时,通过AnnotatedBeanDefinitionReader向容器了加载了5个默认的后置增强器,ConfigurationClassPostProcessor是其中之一。
在这里插入图片描述
下面进入prepareContext
在这里插入图片描述
load(context, sources.toArray(new Object[0]));将启动类添加载到容器中,后续将根据这个配置类进行其他Bean的装配
在这里插入图片描述

2.2.2.4 refreshContext()

再回到run方法,prepareContext为应用上下文设置Environment、注册一些必要的组件,主要看refreshContext(context)–> refresh(context); -->((AbstractApplicationContext) applicationContext).refresh();
在这里插入图片描述
这里执行的是ServletWebServerApplicationContext中的refresh,super.refresh()就是前面讲的容器的启动流程。这里关注一下容器启动阶段的invokeBeanFactoryPostProcessors方法中,执行后置增强器ConfigurationClassPostProcessor,因为Bean根据@Configuration装配是在这里开始的。前面已经讲过ConfigurationClassPostProcessor被加载到了容器,因此会调用它的postProcessBeanDefinitionRegistry方法,跟代码看看
在这里插入图片描述

翻译一下注释:从registry中的配置类进一步加载BeanDefinition。
registry是存放BeanDefinition的地方,配置类就是加了@Configuration的类。
最终就是说,从已经加载到容器中的配置类进一步加载Bean,此时的配置类只有启动类加载到了容器

processConfigBeanDefinitions(registry);–>parser.parse(candidates);–>parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());–>processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);

在这里插入图片描述
这里递归处理配置类及其父类层次结构。doProcessConfigurationClass下节手动与自动装配再讲。

2.2.2.5 callRunners()

SpringBoot启动完成之后调用callRunners()
在这里插入图片描述
进去看看
在这里插入图片描述
找到所有实现了ApplicationRunner、CommandLineRunner接口的类,执行他们的run方法。可以用来在SpringBoot项目启动后马上执行一些任务,比如初始化的任务

2.3 Tomcat启动流程

容器启动流程中会调用onRefresh()方法。ServletWebServerApplicationContext重写了这个方法,在里面启动了web服务,开启了Tomcat的启动流程。 refreshContext(context)执行完之后,Springboot的启动流程差不多就完了,接着看看Tomcat的启动流程,启动入口就在ServletWebServerApplicationContext.onRefresh调用的createWebServer(),跟进去
在这里插入图片描述
servletContext为null,进入if,先获取一个ServletWebServerFactory,进入getWebServerFactory在这里插入图片描述
从容器中取出ServletWebServerFactory,它是通过配置类ServletWebServerFactoryConfiguration被容器加载的,自动装配的时机是在容器启动阶段的invokeBeanFactoryPostProcessors方法中进行,而onRefresh是在它之后被调用的,因此可以获取到ServletWebServerFactory的实例。

2.3.1 getWebServer()

返回到createWebServer(),从this.webServer = factory.getWebServer(getSelfInitializer());进入方法getWebServer
在这里插入图片描述
SpringBoot默认采用Tomcat(ServletWebServerFactoryConfiguration条件配置),因此进入TomcatServletWebServerFactory。这块先做了一些Tomcat属性的设置。进入getTomcatWebServer(tomcat);–>new TomcatWebServer(tomcat, getPort() >= 0);
在这里插入图片描述
进入实例化方法initialize();
在这里插入图片描述
启动tomcat服务,this.tomcat.start()是tomcat的代码,就不进入细看了

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值