首先我们大致了解一下ApplicationContext的加载流程:
由于Spring的源码极为复杂,因此我们不可能再像了解其他框架那样直接自底向上逐行干源码了(可以自己点开看看,代码量非常之多),我们可以先从一些最基本的接口定义开始讲起,自顶向下逐步瓦解,那么我们来看看ApplicationContext
最顶层接口是什么,一直往上,我们会发现有一个AbstractApplicationContext
类,我们发现最顶层实际上是一个BeanFactory接口,那么我们就从这个接口开始研究起。我们可以看到此接口中定义了很多的行为:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.beans.factory;
import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String var1) throws BeansException;
<T> T getBean(String var1, Class<T> var2) throws BeansException;
Object getBean(String var1, Object... var2) throws BeansException;
<T> T getBean(Class<T> var1) throws BeansException;
<T> T getBean(Class<T> var1, Object... var2) throws BeansException;
<T> ObjectProvider<T> getBeanProvider(Class<T> var1);
<T> ObjectProvider<T> getBeanProvider(ResolvableType var1);
boolean containsBean(String var1);
boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;
@Nullable
Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
@Nullable
Class<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException;
String[] getAliases(String var1);
}
我们发现,其中最眼熟的就是getBean()
方法了,此方法被重载了很多次,可以接受多种参数,因此,我们可以断定,一个IoC容器最基本的行为在此接口中已经被定义好了,也就是说,所有的BeanFactory实现类都应该具备容器管理Bean的基本能力,就像它的名字一样,它就是一个Bean工厂,工厂就是用来生产Bean实例对象的。
我们可以直接找到此接口的一个抽象实现AbstractBeanFactory
类,它实现了getBean()
方法:
public Object getBean(String name) throws BeansException {
return this.doGetBean(name, (Class)null, (Object[])null, false);
}
那么我们`doGetBean()`接着来看方法里面干了什么:
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
String beanName = this.transformedBeanName(name);
Object sharedInstance = this.getSingleton(beanName);
Object beanInstance;
if (sharedInstance != null && args == null)
因为所有的Bean默认都是单例模式,对象只会存在一个,因此它会先调用父类的`getSingleton()`方法来直接获取单例对象,如果有的话,就可以直接拿到Bean的实例。如果没有会进入else代码块,我们接着来看,首先会进行一个判断:
if (this.isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
这是为了解决循环依赖进行的处理,比如A和B都是以原型模式进行创建,而A中需要注入B,B中需要注入A,这时就会出现A还未创建完成,就需要B,而B这时也没创建完成,因为B需要A,而A等着B,这样就只能无限循环下去了,所以就出现了循环依赖的问题(同理,一个对象,多个对象也会出现这种情况)但是在单例模式下,由于每个Bean只会创建一个实例,Spring完全有机会处理好循环依赖的问题,只需要一个正确的赋值操作实现循环即可。那么单例模式下是如何解决循环依赖问题的呢?
我们回到`getSingleton()`方法中,单例模式是可以自动解决循环依赖问题的:
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
//先从第一层列表中拿Bean实例,拿到直接返回
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
//第一层拿不到,并且已经认定为处于循环状态,看看第二层有没有
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized(this.singletonObjects) {
//加锁再执行一次上述流程
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
//仍然没有获取到实例,只能从singletonFactory中获取了
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
//丢进earlySingletonObjects中,下次就可以直接在第二层拿到了
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
看起来很复杂,实际上它使用了三层列表的方式来处理循环依赖的问题。包括:
* singletonObjects
* earlySingletonObjects
* singletonFactories
当第一层拿不到时,会接着判断这个Bean是否处于创建状态`isSingletonCurrentlyInCreation()`,它会从一个Set集合中查询,这个集合中存储了已经创建但还未注入属性的实例对象,也就是说处于正在创建状态,如果说发现此Bean处于正在创建状态(一定是因为某个Bean需要注入这个Bean的实例),就可以断定它应该是出现了循环依赖的情况。
earlySingletonObjects相当于是专门处理循环依赖的表,一般包含singletonObjects中的全部实例,如果这个里面还是没有,接着往下走,这时会从singletonFactories中获取(所有的Bean初始化完成之后都会被丢进singletonFactories,也就是只创建了,但是还没进行依赖注入的时候)在获取到后,向earlySingletonObjects中丢入此Bean的实例,并将实例从singletonFactories中移除。
我们最后再来梳理一下流程,还是用我们刚才的例子,A依赖于B,B依赖于A:
1. 假如A先载入,那么A首先进入了singletonFactories中,注意这时还没进行依赖注入,A中的B还是null
* singletonFactories:A
* earlySingletonObjects:
* singletonObjects:
2. 接着肯定是注入A的依赖B了,但是B还没初始化,因此现在先把B给载入了,B构造完成后也进了singletonFactories
* singletonFactories:A,B
* earlySingletonObjects:
* singletonObjects:
3. 开始为B注入依赖,发现B依赖于A,这时又得去获取A的实例,根据上面的分析,这时候A还在singletonFactories中,那么它会被丢进earlySingletonObjects,然后从singletonFactories中移除,然后返回A的实例(注意此时A中的B依赖还是null)
* singletonFactories:B
* earlySingletonObjects:A
* singletonObjects:
4. 这时B已经完成依赖注入了,因此可以直接丢进singletonObjects中
* singletonFactories:
* earlySingletonObjects:A
* singletonObjects:B
5. 然后再将B注入到A中,完成A的依赖注入,A也被丢进singletonObjects中,至此循环依赖完成,A和B完成实例创建
* singletonFactories:
* earlySingletonObjects:
* singletonObjects:A,B
经过整体过程梳理,关于Spring如何解决单例模式的循环依赖理解起来就非常简单了。
现在让我们回到之前的地方,原型模式下如果出现循环依赖会直接抛出异常,如果不存在会接着向下:
//BeanFactory存在父子关系
BeanFactory parentBeanFactory = this.getParentBeanFactory();
//如果存在父BeanFactory,同时当前BeanFactory没有这个Bean的定义
if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
//这里是因为Bean可能有别名,找最原始的那个名称
String nameToLookup = this.originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
//向父BeanFactory递归查找
return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
}
if (args != null) {
//根据参数查找
return parentBeanFactory.getBean(nameToLookup, args);
}
if (requiredType != null) {
//根据类型查找
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
//各种找
return parentBeanFactory.getBean(nameToLookup);
}
也就是说,BeanFactory会先看当前是否存在Bean的定义,如果没有会直接用父BeanFactory各种找。这里出现了一个新的接口`BeanDefinition`,既然工厂需要生产商品,那么肯定需要拿到商品的原材料以及制作配方,我们的Bean也是这样,Bean工厂需要拿到Bean的信息才可以去生成这个Bean的实例对象,而`BeanDefinition`就是用于存放Bean的信息的,所有的Bean信息正是从XML配置文件读取或是注解扫描后得到的。
我们接着来看,如果此BeanFactory不存在父BeanFactory或是包含了Bean的定义,那么会接着往下走,这时只能自己创建Bean了,首先会拿到一个`RootBeanDefinition`对象:
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
下面的内容就非常复杂了,但是我们可以知道,它一定是根据对应的类型(单例、原型)进行了对应的处理,最后自行创建一个新的对象返回。一个Bean的加载流程为:
首先拿到`BeanDefinition`定义,选择对应的构造方法,通过反射进行实例化,然后进行属性填充(依赖注入),完成之后再调用初始化方法(init-method),最后如果存在AOP,则会生成一个代理对象,最后返回的才是我们真正得到的Bean对象。
最后让我们回到`ApplicationContext`中,实际上,它就是一个强化版的`BeanFactory`,在最基本的Bean管理基础上,还添加了:
* 国际化(MessageSource)
* 访问资源,如URL和文件(ResourceLoader)
* 载入多个(有继承关系)上下文
* 消息发送、响应机制(ApplicationEventPublisher)
* AOP机制
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
this.register(componentClasses);
this.refresh();
}
我们发现,无论是还是的构造方法中都会调用`refresh()`方法来刷新应用程序上下文: