spring的bean加載過程


ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
User user = (User) applicationContext.getBean("user");

spring的bean加載是從getBean方法開始的。

一、從緩存中獲取bean
Object sharedInstance = getSingleton(beanName);

protected Object getSingleton(String beanName, boolean allowEarlyReference);

該方法首先嘗試從singletonObjects里面獲取實例,如果獲取不到再從earlySingletonObjects里獲取,如果還獲取不到,再嘗試從sigletonFactories里面獲取beanName對應的ObjectFactory,然后調用這個ObjectFactory的getObject來創建bean,並放到earlySingletonObjects,並將sigletonFactories的對應bean緩存刪除掉。

存儲bean的map解釋:

/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

singletonObjects 用於保存BeanName和創建bean實例之間的關系。

/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

earlySingletonObjects 提前曝光的單例對象緩存,用於解決循環依賴

/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

singletonFactories 用於保存BeanName和創建bean的工廠之間的關系。

內部方法解釋:

public boolean isSingletonCurrentlyInCreation(String beanName);

判斷當前bean是否處於創建中,即正在初始化,但是尚未完成初始化。

allowEarlyReference參數:是否允許從singletonFactories緩存中通過getObject方法拿到bean對象。

二、從bean實例中獲取對象
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd); 

if (!(beanInstance instanceof FactoryBean)) {
			return beanInstance;
   }

object = getObjectFromFactoryBean(factory, beanName, !synthetic);

getBean方法中獲取到的bean,只是原始狀態的bean,不一定是我們想要的。需要調用getObjectForBeanInstance進行處理。getObjectForBeanInstance對非factoryBean不做處理,直接返回,將解析bean的工作委托給getObjectFromFactoryBean

if (factory.isSingleton() && containsSingleton(beanName)) 

Object object = doGetObjectFromFactoryBean(factory, beanName);

getObjectFromFactoryBean方法主要內容是如果是單例則從緩存中獲取,緩存沒有則從factoryBean中獲取。如果不是單例,則直接去從factoryBean中獲取bean.獲取bean的操作又委托給了doGetObjectFromFactoryBean,最終調用 object = factory.getObject(); 獲取bean.

三、獲取bean流程

從spring容器中獲取單例時有兩種情況:緩存中存在和緩存中不存在。在上面緩存中不存在單例bean時,是通過getSingleton的重載方法來實現bean的加載的。

sharedInstance = getSingleton(beanName, () -> {
   try {
      return createBean(beanName, mbd, args);
   }
   catch (BeansException ex) {
      // Explicitly remove instance from singleton cache: It might have been put there
      // eagerly by the creation process, to allow for circular reference resolution.
      // Also remove any beans that received a temporary reference to the bean.
      destroySingleton(beanName);
      throw ex;
   }
});

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory);

主要過程為:

1,再次嘗試從緩存中取出bean

Object singletonObject = this.singletonObjects.get(beanName);

2, 若沒有加載,則記錄beanName的正在加載狀態

beforeSingletonCreation(beanName);

protected void beforeSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}
	
/** Names of beans that are currently in creation. */
	private final Set<String> singletonsCurrentlyInCreation =
			Collections.newSetFromMap(new ConcurrentHashMap<>(16));	
	

3, 通過傳入ObjectFactory創建bean

singletonObject = singletonFactory.getObject();

4,當bean加載結束后需要移除緩存中正在加載狀態

protected void afterSingletonCreation(String beanName) {
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
      throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
   }
}

5,將結果記錄至緩存並刪除加載bean所記錄的各種輔助狀態

addSingleton(beanName, singletonObject);

this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);

四、創建bean

return createBean(beanName, mbd, args);

太長,另起一篇。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM