Spring框架原始碼乾貨分享之三級快取和父子工廠
阿新 • • 發佈:2021-12-16
記錄並分享一下本人學習spring原始碼的過程,有什麼問題或者補充會持續更新。歡迎大家指正!
環境: spring5.X + idea
建議:學習過程中要開著原始碼一步一步過
Spring中物件的建立巨集觀流程:
- 建立物件需要的基礎資料:beanDefinition
在BeanFactory中getBean時做一下三步處理完成物件的建立
- 建立物件:AbstractAutowireCapableBeanFactory中
doCreateBean
createBeanInstance(beanName, mbd, args);
- 屬性賦值:AbstractAutowireCapableBeanFactory
doCreateBean
這裡屬性賦值也就是注入分為多種方式populateBean(beanName, mbd, instanceWrapper);
a. 配置檔案
b. 註解 @Autowired<bean autowired= "bytype|byname"/> <beans default-autowired="bytype|byname"/>
- 物件初始化:AbstractAutowireCapableBeanFactory中
doCreateBean
在初始化的過程中細分了幾個部分分別是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 之前就是建立物件之前做的一些事情
- 獲取bean的id值:transformedBeanName(name)
說明
:從這個方法的命名就可以知道他是用來轉化物件物件名的,Spring配置Bean的時候可以寫id,name,別名,這裡就是把這些轉換成這個物件的唯一id供後續使用。 - 通過當前的id獲取是否有已經建立好的物件:getSingleton(beanName)
說明
:從單例池中獲取物件,然後判斷是否獲取到對應的物件,如果沒有獲取到就執行else去建立,如果獲取到了Spring又做了一個普通物件還是實現了FactoryBean介面的物件,getObjectForBeanInstance,如果是普通物件直接返回,如果是實現了FactoryBean介面物件就會呼叫getObject方法返回。
三級快取
:單例池最根本的實現是Spring設計了一個三級快取,也就是DefaultSingletonBeanRegistry中的三個MapsingletonObjects
一級快取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; }
- 執行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就從父工廠中遞迴查詢,然後例項化對應的物件。如果父工廠中也沒有找到當前的這個物件那就是自己建立,呼叫createBean
到doCreateBean
中執行建立物件的那幾步。
最後
感謝您的閱讀,有什麼意見和問題歡迎評論區留言!書寫不易!
覺得文章對你有幫助記得給我點個贊,歡迎大家關注和轉發文章!