Spring启动流程(大纲)

Spring启动流程(大纲)

本文来盘一盘Spring的启动流程

Spring启动流程过于复杂,如果所有的细节都集中在一篇文章,那是不可能的😂

本文更多的只是一个带你走一遍大致的流程

有些环节的具体执行细节后续会有衍生文章做单独分析,有衍生文章的我都在标题处标注了❗

搭建环境

使用maven创建一个新项目

引入Spring依赖

1
2
3
4
5
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>

Spring配置文件

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>

实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.zhima;

public class Student {
private String name;
private int age;

public Student(String name, int age) {
this.name = name;
this.age = age;
}

public Student() {
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}
}

启动类

在打印cpa的那行打上断点

1
2
3
4
5
6
7
8
9
10
package com.zhima;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Application {
public static void main(String[] args) {
ClassPathXmlApplicationContext cpa = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println(cpa);
}
}

配置一个类型为Student的bean

在applicationContext.xml中添加以下标签

1
<bean id="student" class="com.zhima.Student"/>

调试方式启动查看容器

可以看到容器内已经有了一些bean了,也看到了我们自己配置的student的bean

源码分析

分析框架三板斧

1、找入口(最关键

2、打断点

3、戒贪,只看核心代码(自动忽略try catch和日志相关代码)

分析类三板斧

1、继承体系

2、内部类

3、成员变量

找入口

基于XML的Spring容器的入口比较好找

就是ClassPathXmlApplicationContext的构造方法

继承体系

看一下它的继承体系

它的继承体系十分庞大,但是不要慌,主要的父类就四个

  • AbstractApplicationContext
  • AbstractRefreshableApplicationContext
  • AbstractRefreshableConfigApplicationContext
  • AbstractXmlApplicationContext

打断点

ClassPathXmlApplicationContext

可以看到调用了三个参数的构造方法

refresh方法就是Spring启动流程(大纲)中最最核心的方法

这个方法是在其父类AbstractApplicationContext中的,接下来就围绕着这个方法开始分析

prepareRefresh

见函数名知意,此方法就是为refresh做准备

obtainFreshBeanFactory

AbstractRefreshableApplicationContext#refreshBeanFactory

AbstractXmlApplicationContext#loadBeanDefinitions

❗AbstractXmlApplicationContext#loadBeanDefinitions

XmlBeanDefinitionReader解析xml的过程会放在衍生文章《Spring启动流程(大纲)-解析XML》里面

这里只需要知道它将xml中我们定义的那些bean转化成了BeanDefinition对象

还记得刚刚创建读取器的时候传入了beanfactory吗

这个时候读取器加载的这些BeanDefinition对象已经在beanfactory中了

prepareBeanFactory

postProcessBeanFactory

给子类的拓展点,用来做一些beanFactory初始化后的一些工作

❗invokeBeanFactoryPostProcessors

在BeanFactory根据BeanDefinitions创建对象之前,需要经过一些BeanFactoryProcessor的postProcessBeanFactory方法

ConfigurationClassPostProcessor


为什么已经有postProcessBeanFactory拓展点了还需要有BeanFactoryPostProcessor?

它两提供拓展点的对象不同

postProcessBeanFactory是给子类容器拓展的

BeanFactoryPostProcessor是给用户拓展的

❗registerBeanPostProcessors

注册可以介入bean创建的BeanPostProcessor实例

可以看到这里也是调用的PostProcessorRegistrationDelegate的静态方法

和刚刚invokeBeanFactoryPostProcessors中调用的是同一个类

这两块的分析会放在衍生篇《Spring启动流程(大纲)-后处理器》

initMessageSource

MessageSource是用于国际化的

如果用户注册了一个MESSAGE_SOURCE_BEAN_NAME(messageSource)的Bean,就会使用用户自定义的

否则就使用默认的DelegatingMessageSource

❗initApplicationEventMulticaster

Spring的事件发布组播器

和初始化messageSource的逻辑很像

先看用户有没有定义beanName是APPLICATION_EVENT_MULTICASTER_BEAN_NAME(applicationEventMulticaster)的Bean

有的话就使用用户定义的

否则就使用SimpleApplicationEventMulticaster

Spring的事件机制会在衍生篇《Spring启动流程(大纲)-事件》

onRefresh

registerListeners

注册监听器

❗finishBeanFactoryInitialization

ConversionService是用来做类型转换工作的,和刚刚初始化messageSource的动作很像,也是先看用户有没有自定义

有则用之,无则默认

beanFactory.preInstantiateSingletons是真正执行创建Bean的方法

Spring的Bean的生命周期会在衍生篇《Spring启动流程(大纲)-Bean生命周期》

finishRefresh

initLifecycleProcessor

LifecycleProcessor

来看看这个LifecycleProcessor到底是何方神圣

它是一个Lifecycle的子接口

这个Lifecycle不知道大家还有没有印象了,在ClassPathXmlApplicationContext的继承体系中出现过

并且实现了接口

那这个start是谁来调用的呢?就是这个LifecycleProcessor!

finishRefresh中往下看

现在我们没有自定义LifecycleProcessor,所以我们来看看他默认的实现类DefaultLifecycleProcessoronRefresh中做了些什么

本人技术水平有限,文章中难免会出现错误,读者如有发现,感谢各位指正!

给作者买杯咖啡吧~~~