引言
循环依赖以及创建bean的过程
什么是循环依赖?
我们直接从书中截一张图
循环依赖是无法解决的,除非有终结条件,否则就是死循环,最终导致内存溢出错误
构造依赖分为三种情况
- 构造器循环依赖
这种循环依赖是无法解决的,最终只能抛出异常表示循环依赖 -
setter循环依赖
只能解决单例作用域的循环依赖.通过提前暴露一个单例工厂方法,使得其他的bean能够使用到该bean
最后通过A的ObjectFactory获取了A的对象
- prototype
直接报出异常
然后我们继续来聊创建bean的过程,在上一篇的文章中,我们执行了Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
如果创建了代理的对象,或者说是改变了bean,就要进行常规的创建bean的操作了
try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
我们进入到这个doCreateBean中
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
首先就是这个createBeanInstance方法,这个方法就是根据不同的策略来创建BeanWrapper,
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
如果工厂方法不是空的,那么通过工厂方法来创建
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
这里就是根据参数来锁定构造方法和对应的工厂方法.这里会采用缓存机制.
执行完上面的代码,这个时候就已经确定了要使用哪一个构造函数了,接下来就是实例化的过程了,一个是带注入的,一种是默认的
if (resolved) {
if (autowireNecessary) {
return autowireConstructor(beanName, mbd, null, null);
}
else {
return instantiateBean(beanName, mbd);
}
}
我们来看一下autowireConstructor这种构造方法实例bean的过程,内容较为复杂,我们一点一点分析,
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
这里的explicitArgs是getBean传过来的参数,所以如果这个不为空,我们就可以直接确定它了,如果为空我们就从缓存中获取
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
constructorToUse = (Constructor>) mbd.resolvedConstructorOrFactoryMethod;
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached constructor...
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
if (argsToResolve != null) {
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
}
这里获得的可能是最初类型,也有可能是最终类型,需要和配置参数完全一致.
如果传入的参数为空,缓存也是空,这个时候就要从配置文件中读取,具体代码如下
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
构造函数的参数和构造函数全部确定,转换一下构造函数的类型.然后就是根据实例化策略来实例化bean.
以上就是带参数的构造函数的实例化过程,没有参数的实例化过程就十分的简单.
然后就是实例化策略
如果是普通的就直接通过反射创建,如果有replace或者lookUp