一、DI和IOC的概念
DI和IOC从本质上是从不同角度描述了同一件事情:
- IOC:将对象的控制权交付给框架,由框架管理对象的生命周期,用户使用对象的时候直接从容器按照名称拿即可;(从容器的角度)
- DI:程序通过容器使用对象,在使用容器前需要注入相应的对象名称。(从程序的角度)
从我们开发的使用过程中,通常就是去容器中拿对应的对象,那么这个过程是怎么样的呢?本文将逐步分析IOC的整个流程,其中着重分析了:
- 多级缓存;
- 依赖注入的源码;
- 循环依赖解决。
二、spring容器缓存
在Spring默认的单例实例注册实现类(DefaultSingletonBeanRegistry)中,有多个Map存储不同时期的对象实例:
2.1 singletonObjects
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
在spring容器初始化后,所有的对象都会放入该缓存中。其结构是Map,即beanName为key,Instance为value。
2.2 singletonFactories
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
存储了多个beanFactory,每个bean有自己对应的beanFactory,这是所谓的三级缓存,该缓存的作用是,当程序在任何地方都找不到该bean对应的实例,此时会调用beanFactory来获取bean实例,并放入earlySingletonObjects。因此,有两个很重要的结论:
- earlySingletonObjects 中的bean都是由singletonFactories中的beanName根据beanFactor来创建放入;
- 二者的关系是此消彼长,earlySingletonObjects 拿出一个beanFactory,创建对象放入earlySingletonObjects 时就会从自身中把这个bean删除掉。
注:之所以叫他三级缓存只是因为getSingletion方法会首先查earlySingletonObjects。
2.3 earlySingletonObjects
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
二级缓存用于解决循环依赖问题,该缓存中存储的是半成品实例。
即这些实例在创建时由于其属性中有其他bean的引用,而引用的对象尚未创建(有依赖),此时需要暂停创建当前对象而且创建引用对象(依赖的对象)。此时当前的对象会放到earlySingletonObjects 中(通过singletonFactories ),提前暴露出来(解决循环依赖)。
2.4 registeredSingletons
将bean注册为单例且完整。(这部分我不是很理解)
/** Set of registered singletons, containing the bean names in registration order. */
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
Assert.notNull(beanName, "Bean name must not be null");
Assert.notNull(singletonObject, "Singleton object must not be null");
synchronized (this.singletonObjects) {
Object oldObject = this.singletonObjects.get(beanName);
// 如果该对象已经被加入了singletonObjects,那么说明已经创建完成,无需重复注册
if (oldObject != null) {
throw new IllegalStateException("Could not register object [" + singletonObject +
"] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
}
addSingleton(beanName, singletonObject);
}
}
// 将beanName和实例对象放入singletonObjects和registeredSingletons
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
2.5 singletonsCurrentlyInCreation
/** Names of beans that are currently in creation. */
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
在spring容器创建一个bean时,会首先将beanName 放入该缓存,表示该bean正在被创建。
同理,当创建完成后,也会将该beanName移除该容器。
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
三、 spring容器启动过程(默认是单例实例)
- 加载配置文件,创建beanFactory;
- 获取配置文件中的对于Bean的definition,以便于构造对象和注入属性;
- fresh beanFactory,同时初始化bean实例(单例);
- 注册所有的单例bean并返回可用的容器引用。
3.1 bean的创建
大致流程如下:
- 将当前的beanName标记为正在创建;
- 使用initializeBean方法初始化实例(此时只有一个对象,没有属性注入);
- 如果支持循环依赖则生成三级缓存,并且尝试提前暴露(如果此时该beanName实例化完成,那么则不会加入缓存)
- 填充bean属性,初始化bean,这里可能会出现循环依赖从而引发别的bean的实例化,但是此时当前的bean已经放入beanFactories中了;
- 处理循环依赖,这里需要注意对于动态代理中的循环依赖的处理。在之后会单独讲解。
- 此时bean已经可以被使用,并尝试注册bean;
- 将bean放入容器中(一级缓存),标记已创建完成并删除二三级缓存的内容。
AbstractAutowireCapableBeanFactory中的createBean方法(做了一些安全性的保证)调用了doCreateBean方法(实际创建的方法):
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// 创建BeanWrapper和保存bean的class对象到mbd中
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// 先从缓存中看看能不能读出BeanWrapper
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
......
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
.......
// 决定是否开启二三级缓存解决循环依赖
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
// 如果允许循环依赖(即会处理循环依赖),会将该beanName提前暴露
if (earlySingletonExposure) {
.......
/* addSingletonFactory的主要逻辑
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
*/
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// 注入Bean的属性,其实啥都没做,就是返回一个空的实例
populateBean(beanName, mbd, instanceWrapper);
/* 初始化bean, 主要调用了invokeAwareMethods,该方法的作用是:
1. 设置beanName,
2. 设置类加载器,
3. 设置beanFactory
*/
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
.......
// 允许提前暴露
if (earlySingletonExposure) {
// 如果第二个参数为false
//getSingleton只会去singletonObjects和earlySingletonObjects中找,不会调用beanFactory创建
Object earlySingletonReference = getSingleton(beanName, false);
/*
此时如果从getSingleton方法中获取到了实例
说明该bean是由于产生了循环依赖而导致从beanFactory中生成了bean并暴露出来
*/
if (earlySingletonReference != null) {
// exposedObject == bean是用来解决动态代理类的
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
/* 处理循环依赖
allowRawInjectionDespiteWrapping :
在循环引用的情况下,如果注入的bean被代理,是否要注入原始bean实例
*/
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
// 抛出异常
}
}
}
}
......
return exposedObject;
}
3.2 getSingleton的代码逻辑:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 直接尝试从容器中获取bean
Object singletonObject = this.singletonObjects.get(beanName);
// 如果该单例对象没有被创建或者正在被创建
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 从early reference cache中获取:即该对象是否是由于循环依赖而提前暴露
singletonObject = this.earlySingletonObjects.get(beanName);
// 如果还没有获取到,则需要创建该对象,注意此时必须要允许allowEarlyReference
if (singletonObject == null && allowEarlyReference) {
// 先上锁,即别的线程无法调用下面的代码
synchronized (this.singletonObjects) {
// 此时还需要再次获取一下,因为从第一次快速获取到现在可能别的线程创建了该bean
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 和上面同理
singletonObject = this.earlySingletonObjects.get(beanName);
// 如果还没有,从singletonFactories缓存中获取创建该bean的bean factory
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
// 如果获取到了,则通过singletonFactory创建该bean
if (singletonFactory != null) {
/*
1. 从singletonFactory中申请一个对象实例;
2. 放入earlySingletonObjects中;
3. 从singletonFactory移除beanName;
*/
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
四、获取bean的过程
4.1 getBean(AbstractApplicationContext)
调用BeanFactory
的getBean方法。
public Object getBean(String name) throws BeansException {
// 这里会检测BeanFactory是否正在刷新或者已经关闭,如果没有抛出异常说明BeanFactory正常,可以获取bean
this.assertBeanFactoryActive();
return this.getBeanFactory().getBean(name);
}
4.2 调用doGetBean
String beanName = transformedBeanName(name);
// getSingleton方法
Object sharedInstance = getSingleton(beanName);
4.3 调用getSingleton(DefaultSingletonBeanRegistry)
该方法会返回注册的单例对象,并且检查安全性:
- 是否是已经创建好的对象;
- 对当前创建的单例的早期引用(解决循环引用)。
五、循环依赖解决
5.1 常规场景
说明一个场景:A与B之间存在循环依赖:
5.2 针对AOP过程中出现的循环依赖
其主要的处理逻辑在于下面的这段代码:
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
为什么在获取到了earlySingletonReference (必定存在循环依赖)的时候还要exposedObject == bean?我的理解是:
在进行对象初始化时(exposedObject = initializeBean(xxxx)),如果需要进行aop的话会调用:
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
exposedObject 其实指向的是被代理后的对象,而bean引用指向的还是原始对象。
- 如果exposedObject == bean,说明此时没有发送AOP,可以直接返回;
- exposedObject != bean,说明发生了AOP行为,处理AOP中的循环依赖。下面会继续解释。
5.3 为什么要使用二三级缓存?
二级缓存:earlySingletonObjects;
三级缓存:singletonFactories。
二级缓存就是用来存储创建到一半的对象,这些对象无法直接使用,但是可以解决循环依赖这个过程,因为已经可以拿到引用了。
二级缓存中的对象由三级缓存中的BeanFactory中创建,也就是三级缓存中只是提供了创建对象的方法。这样的好处是:
- 降低了没有必要的对象创建的开销;
- 将对bean实例的依赖转化成了对beanFactory的依赖,这样做的好处是可以解决动态代理的过程中出现的循环依赖。
如果两个对象A,B都需要AOP且存在循环依赖,那么过程是先创建A,在创建A的时候触发创建B,B创建并要获取A代理后的对象,此时会去一二级缓存中发现没有,此时再去singletonFactories创建早期对象,即调用getEarlyBeanReference,此时会检查对象是否需要被代理:hasInstantiationAwareBeanPostProcessors。如果需要就提前生成代理后的对象并放入二级缓存中。
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
return exposedObject;
}