死磕spring,大致還原spring的bean載入過程
總的來說:
- 對傳入的name做轉化,去除&開頭獲得真實beanname,通過aliasMap獲取是否有別名
- 檢查是否有bean的完整的引用快取;如果沒有,看singletonsCurrentlyInCreation,是不是這個bean正在建立中,看earlySingletonObjects中有沒有半成品的bean(初始化但沒有set屬性);如果還沒有,就用beanFactory獲取建立中的半成品bean,放入earlySingletonObjects,同時把objectFactory移除;如果beanFactory還沒有,那就是真沒有了
- 判斷上一步中返回的bean,如果name不是&開頭且實現factoryBean的,使用factoryBean.getObject方法獲取bean,否則直接返回bean。如果上一步獲取不到bean,走下一步建立bean(針對singleton)
- beanName放到singletonsCurrentlyInCreation中,表示這個bean正在建立中;獲取類定義,建立一個半成品的bean,建立ObjectFactory,放到singletonFactories中快取,這個ObjectFactory重寫了getObject方法,返回的是建立的半成品bean;其他地方拿不到快取的完整引用bean,可以拿這個快取ObjectFactory獲取半成品的bean;populateBean設定屬性,將完整的bean放到singletonObjects中快取,移除之前的singletonsCurrentlyInCreation和ObjectFactoryMap,earlySingletonObjects。
具體步驟分析:
先看AbstractBeanFactory這個類,通過beanname獲取Bean物件,後面主要分析doGetBean方法,無特殊說明都是這個類裡的程式碼
public Object getBean(String name) throws BeansException {
return this.doGetBean(name, (Class)null, (Object[])null, false);
}
1、解析name,如果name是以&開頭的,要去除&。然後aliasMap中檢視有沒有別名,獲取最終的beanName
protected <T> T doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { final String beanName = this.transformedBeanName(name); ....... }
2、從快取中獲取bean引用,spring只快取singleton型別bean。
protected <T> T doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
.......
Object sharedInstance = this.getSingleton(beanName);
.........
}
DefaultSingletonBeanRegistry類:
allowEarlyReference表示是否允許由ObjectFactory獲取半成品的bean。半成品bean是指初始化了bean,但是沒有通過set方法設定屬性。
//快取完整的bean引用
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
//快取baen的工廠物件
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
//快取半成品的bean
private final Map<String, Object> earlySingletonObjects = new HashMap(16);
//表示beanName對應的bean正在建立中
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap(16));
public Object getSingleton(String beanName) {
return this.getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if(singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
Map var4 = this.singletonObjects;
synchronized(this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if(singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if(singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject != NULL_OBJECT?singletonObject:null;
}
步驟說明:
2.1、先從singletonObjects獲取完整的bean引用
2.2、獲取不到,判斷用isSingletonCurrentlyInCreation判斷該bean是否在建立中,從earlySingletonObjects中嘗試獲取,如果獲取不到,嘗試獲取ObjectFactory,使用ObjectFactory獲取半成品bean,並放入earlySingletonObjects中。這個地方為什麼ObjectFactory獲取的是半成品而不是完整的bean呢,因為後面重寫了getObject方法,導致只能獲取半成品。
3、對不為null的bean做處理。
protected <T> T doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
.......
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
.........
}
protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
if(BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(this.transformedBeanName(name), beanInstance.getClass());
} else if(beanInstance instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
Object object = null;
if(mbd == null) {
object = this.getCachedObjectForFactoryBean(beanName);
}
if(object == null) {
FactoryBean<?> factory = (FactoryBean)beanInstance;
if(mbd == null && this.containsBeanDefinition(beanName)) {
mbd = this.getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = mbd != null && mbd.isSynthetic();
object = this.getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
} else {
return beanInstance;
}
}
如果這個beanInstance是實現了FactoryBean介面,且原始的name不是以&開頭的,返回的物件是object是beanInstance.getObject方法返回的物件,這個也是有快取的,先嚐試從快取中獲取。
其他情況就直接返回beanInstance。
此處可以瞭解下FactoryBean的用法,關於ApplicationContext.getBean(beanName),beanName是否加&的區別。
4、對bean==null的處理,重頭戲!
這個地方獲取bean的類定義,然後獲取類的構造器的依賴bean,如果這個地方有構造器迴圈依賴,就報錯了。
final RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
this.checkMergedBeanDefinition(mbd, beanName, args);
String[] dependsOn = mbd.getDependsOn();
String[] var11;
if(dependsOn != null) {
var11 = dependsOn;
int var12 = dependsOn.length;
for(int var13 = 0; var13 < var12; ++var13) {
String dep = var11[var13];
if(this.isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
this.registerDependentBean(dep, beanName);
this.getBean(dep);
}
}
5、判斷這個bean是否是singleton的,如果不是singleton的,建立bean,然後設定屬性就完了。重點還是singleton模式的。以下只討論singleton模式
if(mbd.isSingleton()) {
sharedInstance = this.getSingleton(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
try {
return AbstractBeanFactory.this.createBean(beanName, mbd, args);
} catch (BeansException var2) {
AbstractBeanFactory.this.destroySingleton(beanName);
throw var2;
}
}
});
//6、最後呢也是如同步驟3一樣的細節小處理
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
5.1先看getSingleton方法,這裡建立objectFactory,重寫方法。
DefaultSingletonBeanRegistry類:重點是如下方法
//將beanName放入isSingletonCurrentlyInCreation。
this.beforeSingletonCreation(beanName);
...........
//建立bean,之前重寫的getObject()方法
singletonObject = singletonFactory.getObject();
...........
//將beanName從isSingletonCurrentlyInCreation中移除
this.afterSingletonCreation(beanName);
...........
//將完整的bean引用放入singletonObjects,移除earlySingletonObjects,singletonFactories中引用。
this.addSingleton(beanName, singletonObject);
5.2 初始化bean,set屬性
AbstractAutowireCapableBeanFactory類:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
...........
boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
if(earlySingletonExposure) {
if(this.logger.isDebugEnabled()) {
this.logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
}
this.addSingletonFactory(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
return AbstractAutowireCapableBeanFactory.this.getEarlyBeanReference(beanName, mbd, bean);
}
});
}
Object exposedObject = bean;
try {
//populate方法就是屬性注入,具體可以參考連結:http://www.imooc.com/article/19449
this.populateBean(beanName, mbd, instanceWrapper);
if(exposedObject != null) {
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
}
} catch (Throwable var18) {
if(var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
throw (BeanCreationException)var18;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
}
...........
建立一個半成品的bean,以及一個ObjectFactory,重寫getObject方法,返回這個半成品的bean,這就是前面步驟2。
把這個objectFactory放到singletonFactories中。
if(earlySingletonExposure) {
Object earlySingletonReference = this.getSingleton(beanName, false);
if(earlySingletonReference != null) {
if(exposedObject == bean) {
exposedObject = earlySingletonReference;
} else if(!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
String[] dependentBeans = this.getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
String[] var12 = dependentBeans;
int var13 = dependentBeans.length;
for(int var14 = 0; var14 < var13; ++var14) {
String dependentBean = var12[var14];
if(!this.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 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
上面這段程式碼就是判斷建立的bean的引用和earlySingletonObjects中的引用是否一樣,如果不一樣,判斷這個bean是否被其他bean依賴,如果沒有依賴就刪除所有引用,重新替換,如果有依賴的話就報錯了。
迴圈依賴的不同情況
1、構造器迴圈依賴,如步驟4所示,直接失敗了。
2、singleton模式的,set迴圈依賴,可以解決。A依賴B,B依賴C,C依賴A,那麼在set屬性的時候會一直迴圈建立bean,直到C拿到A半成品引用。特殊在bean的建立是先初始化,然後set屬性。
3、其他模式的,set迴圈依賴,不可以解決。