springboot启动流程分析

背景

我们目前大多数的公司都已经基于SpringBoot开发,SpringBoot确实给我们解放了生产力,但是我们是否应该好好研究一下它的加载机制,以及相关的自动加载的一些流程,SpringBoot到底是如何进行相关地启动加载工作的。另外的其实很多公司面试的时候也是比较喜欢问一下SpringBoot的启动流程,所以,我们就从源码入手,对其好好研究一下。我们就从一步一步debug代码来进行分析吧。

创建一个简单工程

我们就比较简单地通过Spring Initializr的方式创建一个工程,如下图,当然我们也可以直接在相关的官网上进行创建基础demo,然后将其下载下来,官网地址:https://start.spring.io/
创建工程

为了后面能够更好地查看容器类型的源码,我们让springboot支持web,我们添加如下pom依赖:

1
2
3
4
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>

我们找到对应的应用程序的入口,并且给其入口打上断点,如下图
断点入口

按住F7(本人的是mac,直接按住fn+f7)进入断点,我们先看到进入run方法之后如下:

1
2
3
4
5
6
7
public static ConfigurableApplicationContext run(Class primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}

public static ConfigurableApplicationContext run(Class[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}

走到这步之后,直接进入其对应的SpringApplication的构造函数,我们看看SpringApplication构造器里面做了哪些东西:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
/***这上面有一些属性的设置,暂时忽略不看,我们看核心的地方***/
this.resourceLoader = resourceLoader; // 资源加载器
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
// 1. 可能的web应用程序的类型。
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 2. 设置初始化应用context
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 3.设置初始化监听
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
// 4. 推演主程序类
this.mainApplicationClass = this.deduceMainApplicationClass();
}

接下来我们先看一下获取web应用程序类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    private static final String[] SERVLET_INDICATOR_CLASSES = new String[]{"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"};

static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
return REACTIVE;
} else {
String[] var0 = SERVLET_INDICATOR_CLASSES;
int var1 = var0.length;

for(int var2 = 0; var2 < var1; ++var2) {
String className = var0[var2];
if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
return NONE;
}
}
//返回servlet
return SERVLET;
}
}

由于我们一开始即成了web的maven依赖,所以当前debug下来,返回给我们的是servlet容器。

从源码中我们可以看出其实web的应用程序有三种,分别如下:

1
2
3
NONE,//表示不是web应用
SERVLET,//servlet容器,标示为web应用
REACTIVE;// 反应型web应用(webflux)

上述提到webflux(说实话,还没仔细研究,官网意思大概是这样的Spring WebFlux 是一套全新的 Reactive Web 栈技术,实现完全非阻塞),后面打算专门出一篇文章去研究一下。

拿到类型之后继而初始化应用上下文。具体debug进去看一下源代码:

1
2


Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×