spring學習-分步getBean方法(1)
阿新 • • 發佈:2019-02-07
所有spring在初始化完成BeanDefinition以後(預設使用的是GenericBeanDefinition)後。在使用spring容器裡的bean例項時,我們一般都是通過getBean方法實現的。例如
private ClassPathXmlApplicationContext context; @Before public void setUp() throws Exception { context = new ClassPathXmlApplicationContext("classpath*:gg/spring/context.xml"); } @Test public void testLoadBean() { //獲取spring的bean例項 context.getBean("test1"); }
其中ClassPathXmlApplicationContext的方法getBean,是呼叫了AbstractApplicationContext裡的getBean方法。而AbstractApplicationContext的getbean方法呼叫了beanFactory窗器是的getBean方法,此時的beanFactory是使用具體實現類是DefaultListableBeanFactory類,getBean方法是呼叫的父類AbstractBeanFactory的getBean實現
public Object getBean(String name) throws BeansException { return getBeanFactory().getBean(name); }
AbstractBeanFactory的getBean方法程式碼如下,其中呼叫了doGetBean方法,引數為name:bean的名稱,
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(final String name, final Class<T> requriedType, final Object[] args, boolean typeCheckOnly) { //生成beanName,如果是factorybean的name,去除factorybean的第一位標記& //判斷當前beanName是否是別名,如果是別名,取對應的真實的beanName final String beanName = transformedBeanName(name); Object bean; //獲取對應的已經建立的單例bean,這裡呼叫的是DefaultSingletonRegistry.getSingleton(beanName),實際呼叫的是DefaultSingletonRegistry.getSingleton(beanName, true) //其中DefaultSingletonRegistry.getSingleton(beanName, true)以下詳細說明 Object shareInstance = getSingleton(beanName);
DefaultSingletonRegistry.getSingleton(beanName, true)說明
/**
* 此處方法用於spring處理迴圈依賴。A-->B,B-->C,C-->A,A中方法setB,B中方法setC,C中方法setA
* 建立A例項後初始化A的屬性,發現需要引用B,去建立B,建立B例項後初始化B的屬性時需要引用C,會去建立C例項後初始化C的屬性,此時的singletonsCurrentLyInCreation中包括A,B,C
* 此時C又引用了A,需要再次去建立A,而這時A只是生成物件,但A的還沒有真正建立完成,(if (singletonObject == null && isSingletonCurrentlyInCreation(beanName))為true)
* 此時取A的依賴建立快取(earlySingletonObjects),還是沒有例項,預設是允許早期依賴建立(if (singletonObject == null && allowEarlyReference) == true)
* 這時去取A的建立工廠,singletonFactoryies中,是在A例項化後寫入一個簡單的依賴工廠類,可以參考方法AbstractAutowireCapableBeanFactory.doCreateBean方法,
* 這時通過依賴工廠得到的A的例項其他就是之前A建立的,但沒有初始化屬性的物件。
* 之後C的例項化完成-->B的例項化完成-->A的例項化完成。
* @param beanName
* @param allowEarlyReference
* @return
*/
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//先從快取中獲取例項
Object singletonObject = this.singletonObjects.get(beanName);
//如果級存中不存在,並且beanName是正在建立的beanName(singletonsCurrentlyInCreation,在建立例項時會寫入,說明有依賴迴圈依賴的情況)
//isSingletonCurrentlyIncreation說明
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (singletonObject) {
//查詢是否有依賴這個bean的例項
singletonObject = this.earlySingletonObjects.get(beanName);
//如果沒有並且允許迴圈依賴建立
if (singletonObject == null && allowEarlyReference) {
//找到建立這個bean的工廠類,並建立這個bean.同時放到早期的快取中,並移除這個建立工廠,不再建立,這個建立工廠只是簡單的返回之前例項的物件
ObjectFactory objectFactory = this.singletonFactories.get(beanName);
if (objectFactory != null) {
singletonObject = objectFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT) ? singletonObject : null;
}
AbstractAutowireCapableBeanFactory中的doCreateBean方法裡有以下內容,此處的addSinletonFactory是呼叫的DefaultSingletonRegistry的addSingletonFactory方法
//此處判斷當前的bean是否正在建立中,並且允許迴圈依賴,spring所有單例在建立過程中都會臨時存放一個依賴的建立工廠,當spring建立成功之後,會移除建立工廠類
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, new ObjectFactory() {
public Object getObject() {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
DefaultSingletonRegistry.addSingletonFactory方法實現如下protected void addSingletonFactory(String beanName, ObjectFactory objectFactory) {
Assert.notNull(objectFactory, "Object factory must not be null");
synchronized (singletonObjects) {
if (!singletonObjects.containsKey(beanName)) {
//bean對應的建立工廠類
this.singletonFactories.put(beanName, objectFactory);
//移除存放的早期以來
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
此處有一個地方需要注意的是,spring在建立單例的依賴工廠時,會呼叫bean中的甩的的SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference對早期依賴的物件進行處理
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor)bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
if (exposedObject == null) {
return exposedObject;
}
}
}
}
return exposedObject;
}