Spring启动流程
本文来盘一盘Spring的启动流程
Spring启动流程过于复杂,如果所有的细节都集中在一篇文章,那是不可能的😂
本文更多的只是一个带你走一遍大致的流程
有些环节的具体执行细节后续会有衍生文章做单独分析,有衍生文章的我都在标题处标注了❗
搭建环境
使用maven创建一个新项目
引入Spring依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
Spring配置文件
<?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>
实体类
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的那行打上断点
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中添加以下标签
<bean id="student" class="com.zhima.Student"/>
调试方式启动查看容器
可以看到容器内已经有了一些bean了,也看到了我们自己配置的student的bean
找入口
基于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,所以我们来看看他默认的实现类DefaultLifecycleProcessor
在onRefresh
中做了些什么
本人技术水平有限,文章中难免会出现错误,读者如有发现,感谢各位指正!