1. 程式人生 > 其它 >Spring框架原始碼乾貨分享之三級快取和父子工廠

Spring框架原始碼乾貨分享之三級快取和父子工廠

記錄並分享一下本人學習spring原始碼的過程,有什麼問題或者補充會持續更新。歡迎大家指正!

環境: spring5.X + idea

建議:學習過程中要開著原始碼一步一步過

Spring中物件的建立巨集觀流程:

  1. 建立物件需要的基礎資料:beanDefinition

在BeanFactory中getBean時做一下三步處理完成物件的建立

  1. 建立物件:AbstractAutowireCapableBeanFactorydoCreateBean
    createBeanInstance(beanName, mbd, args);
    
  2. 屬性賦值:AbstractAutowireCapableBeanFactory
    doCreateBean
    populateBean(beanName, mbd, instanceWrapper);
    
    這裡屬性賦值也就是注入分為多種方式
    a. 配置檔案
    <bean autowired= "bytype|byname"/> 
    <beans default-autowired="bytype|byname"/>
    
    b. 註解 @Autowired
  3. 物件初始化:AbstractAutowireCapableBeanFactorydoCreateBean
    initializeBean(beanName, exposedObject, mbd);
    
    在初始化的過程中細分了幾個部分分別是
    a. aware
    b. BeanPostProcessors
    c. InitMethods

巨集觀流程瞭解清楚了之後,先分析一下createBean之前spring做了那些事,也就是Beanfactory呼叫doGetBean然後執行createbean呼叫AbstractAutowireCapableBeanFactory中的doCreateBean之前Spring還做了什麼樣的處理

上原始碼(createbean執行之前)

String beanName = this.transformedBeanName(name);
Object sharedInstance = this.getSingleton(beanName);
Object bean;
if(sharedInstance != null && args == null) {
//日誌列印的
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
} else {
}

原始碼說明:else 之前就是建立物件之前做的一些事情

  1. 獲取bean的id值:transformedBeanName(name)
    說明:從這個方法的命名就可以知道他是用來轉化物件物件名的,Spring配置Bean的時候可以寫id,name,別名,這裡就是把這些轉換成這個物件的唯一id供後續使用。
  2. 通過當前的id獲取是否有已經建立好的物件:getSingleton(beanName)
    說明:從單例池中獲取物件,然後判斷是否獲取到對應的物件,如果沒有獲取到就執行else去建立,如果獲取到了Spring又做了一個普通物件還是實現了FactoryBean介面的物件,getObjectForBeanInstance,如果是普通物件直接返回,如果是實現了FactoryBean介面物件就會呼叫getObject方法返回。
    三級快取:單例池最根本的實現是Spring設計了一個三級快取,也就是DefaultSingletonBeanRegistry中的三個Map
    • singletonObjects 一級快取
    • earlySingletonObjects 二級快取
    • singletonFactories 三級快取
      protected Object getSingleton(String beanName, boolean allowEarlyReference) {
      Object singletonObject = this.singletonObjects.get(beanName);
      	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      		synchronized (this.singletonObjects) {
      			singletonObject = this.earlySingletonObjects.get(beanName);
      			if (singletonObject == null && allowEarlyReference) {
      				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
      				if (singletonFactory != null) {
      					singletonObject = singletonFactory.getObject();
      					this.earlySingletonObjects.put(beanName, singletonObject);
      					this.singletonFactories.remove(beanName);
      				}
      			}
      		}
      	}
      	return singletonObject;
      }
      
  3. 執行else分支時Spring在呼叫createbean方法之前還做了一些父子工廠相關的處理
    說明:如果存在父子工廠,那麼他們的配置會融合,發現同名配置會優先使用子工廠中的配置
    BeanFactory parentBeanFactory = this.getParentBeanFactory();
    if(parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
       String nameToLookup = this.originalBeanName(name);
       if(parentBeanFactory instanceof AbstractBeanFactory) {
          return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
        }
       if(args != null) {
          return parentBeanFactory.getBean(nameToLookup, args);
        }
       if(requiredType != null) {
         return parentBeanFactory.getBean(nameToLookup, requiredType);
        }
        return parentBeanFactory.getBean(nameToLookup);
     }
    
    說明:獲取父類工廠,如果存在父工廠並且子工廠中沒有對應的BeanDefinition就從父工廠中遞迴查詢,然後例項化對應的物件。如果父工廠中也沒有找到當前的這個物件那就是自己建立,呼叫createBeandoCreateBean中執行建立物件的那幾步。

最後

感謝您的閱讀,有什麼意見和問題歡迎評論區留言!書寫不易!
覺得文章對你有幫助記得給我點個贊,歡迎大家關注和轉發文章!