目錄html
以前開了一個解讀IOC容器啓動源碼的坑Spring IOC容器啓動流程源碼解析(一)——容器概念詳解及源碼初探,不過因爲最近比較忙,這個坑挖了卻一直沒時間填。最近在看分佈式事務相關的開源項目,碰到了一些Spring AOP相關的問題,好比Spring AOP中的加強邏輯是什麼時候以何種方式織入目標類中的;多個切面的執行順序如何肯定;如何以反射的方式調用事務方法等等,才發現我對Spring AOP的底層瞭解的仍是太少了。Spring AOP默認使用動態代理的方式在運行時織入切面,這個動態代理對象須要由Spring容器建立並進行管理。於是,深刻了解Spring AOP的前提就是熟悉IOC容器建立一個實例的過程,這個過程清晰了,天然也就找到了繼續深刻研究Spring AOP的入口。趁着這個機會就先來好好梳理下IOC容器建立實例的流程,順便也把解讀IOC容器啓動源碼這個大坑的第四部分(初始化單實例bean)先填了,其實這也是整個IOC容器啓動流程中最重要的階段,這部份內容很是複雜,細節至關多,對這部分的講解主要仍是以梳理流程爲主,知道容器初始化單實例bean的過程分爲哪幾個階段,每一個階段主要作了哪些工做,解決了哪些重要的問題,一些和容器核心功能無關的細節能夠適當忽略,這樣分清主次更有助於理解。前端
整個IOC容器的啓動過程都包含在容器抽象類AbstractApplicationContext
的模板方法refresh()
中
在這以前已經建立了核心容器BeanFactory,完成了bean定義信息的加載解析和註冊,對於用戶定義的每個bean,建立一個對應的BeanDefinition,以beanName爲key,Definition爲value保存在覈心容器beanFactory的map中。
這個時候尚未真正建立Bean,而是建立了一個Bean的設計圖——BeanDefinition,以後能夠根據這個BeanDefinition建立真正的Bean實例。完成核心容器的建立後,還會註冊一些容器的基礎組件,以後纔會來到啓動容器最重要的階段——初始化bean的階段,這部分的入口在finishBeanFactoryInitialization(beanFactory)
方法中,以下箭頭所示
spring
進入finishBeanFactoryInitialization(beanFactory)方法,在真正進行初始化動做前還會有一些準備工做,這部份內容由於不是特別重要,就在這順便說起下
緩存
上面這部分邏輯中,容器提早初始化了兩類特殊的bean,一類是ConversionService,能夠進行屬性值的轉化,好比將前端傳過來的特定格式的時間字符串轉化爲Date對象,功能和PropertyEditor相似;另外一類則是實現了LoadTimeWeaverAware接口的Bean,這部分和Spring中的LTW(LoadTimeWeaving)相關,儘管也是AOP,但並非Spring AOP中的默認實現。初始化時經過調用BeanFactory的getBean(..)方法實現的,這個方法其實才是初始化bean的真正入口,不事後面還會碰到,這裏就跳過。進入箭頭所指的方法,從方法名能夠得知,下面這部分仍是屬於準備階段的次要內容app
//獲取全部BeanDefinition的beanName List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); // Trigger initialization of all non-lazy singleton beans... //遍歷全部beanName for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); //若是bean不是抽象的且單例且非懶加載則經過if條件 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { //若是是實現FactoryBean接口的bean Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); if (bean instanceof FactoryBean) { final FactoryBean<?> factory = (FactoryBean<?>) bean; boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { //初始化bean的真正入口 getBean(beanName); } } } else { //不是FactoryBean則執行這裏,這是初始化bean的真正入口 getBean(beanName); } } }
這裏會拿到以前註冊的全部BeanDefinition,進行初始化的條件判斷,若是Bean被設置爲單例(scope=singleton)且非懶加載(lazy-init=false)則會開始真正的初始化流程,若是這其中任一條件不知足,則在容器啓動的過程當中是不會初始化這個bean的。以後的處理邏輯根據bean是否爲FactoryBean類型而有所不一樣,但最後多會調用getBean()方法,這個方法其實才是初始化bean的真正的入口方法。分佈式
@Override public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); }
這實際上是一個至關通用的方法,它的真正含義實際上是供客戶端從容器中獲取bean,若客戶端想要的bean不存在,容器固然會建立並初始化它,但bean可能已經建立好並緩存在容器中,那麼直接把緩存的對象返回給客戶端就好,因此這個方法的前綴是get而不是create。不過咱們是在IOC容器的啓動流程中去分析這個方法,這個上下文環境下,全部bean都還未建立,因此這就至關於一個初始化方法。進入內部的doGetBean()方法,這個方法比較長,可是流程仍是比較清晰的。ide
這是transformedBeanName(name)作的工做post
//對原始的beanName進行轉化,獲取真實的beanName,若是是FactoryBean則去除前綴'&',若是是別名則經過 //別名獲取真實的名稱 final String beanName = transformedBeanName(name); Object bean;
// 從緩存中獲取bean若緩存中不存在則從其ObjectFactory中獲取,若ObjectFactory不存在則返回null Object sharedInstance = getSingleton(beanName);
這個getSingleton(beanName)比較值得講,一是由於後面還會見到,二是它和spring解決bean循環依賴的方式有關,於是有必要理解其實現原理。ui
@Nullable protected Object getSingleton(String beanName, boolean allowEarlyReference) { //先嚐試從singletonObjects這個緩存map中獲取,這是個全局的緩存,裏面存放着真正建立完成的bean //單例的bean只會被建立一次,以後便會緩存在這個map中供客戶端重複獲取 Object singletonObject = this.singletonObjects.get(beanName); //若是緩存中不存在該name的bean且該bean正在建立過程當中 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { //同步 synchronized (this.singletonObjects) { //嘗試從earlySingletonObjects這個緩存map中獲取bean,這個map中的bean並未真正建立完成 //可是提早暴露出來用來解決依賴問題 singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { //若依舊未獲取到則從singletonFactories這個map中獲取其工廠 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { //成功獲取該bean的工廠實例 //調用工廠方法獲取bean singletonObject = singletonFactory.getObject(); //將該bean加入earlySingletonObjects這個map中 this.earlySingletonObjects.put(beanName, singletonObject); //將建立該bean的工廠從singletonFactories中移除 this.singletonFactories.remove(beanName); } } } } return singletonObject; }
從緩存中獲取bean的流程並不複雜,可是由於涉及到3個Map,因此邏輯有點繞。this
/** * Cache of singleton objects: bean name to bean instance. */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
這個map用來緩存真正建立完成的bean,真正建立完成是指對象存在且全部屬性/依賴已經注入且全部初始化操做已經完成。
/** * Cache of early singleton objects: bean name to bean instance. */ private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
這個map中的bean併爲真正建立完成,可是提早放在這個map中暴露出來,主要是爲了解決循環依賴問題。
/** * Cache of singleton factories: bean name to ObjectFactory. */ private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
這個map中緩存的是用來獲取bean的工廠ObjectFactopry,這個工廠中有一個剛建立完成可是未注入屬性也未進行初始化的bean,當從工廠中取出這個bean後,該bean會緩存到earlySingletonObjects這個map中,而且對應的工廠會從singletonFactories移除。
爲何要搞的這麼複雜?這和Spring解決bean之間的循環依賴的思路有關:Spring在建立Bean A時若是發現A依賴於B會先去建立B,這個發現的時機實際上是在爲A注入屬性時,此時bean A其實已經被建立,可是還未進行任何屬性賦值和初始化操做,此時會將這個原始的bean A封裝在一個ObjectFactory工廠中,保存在singletonFactories緩存,以後在建立B的過程當中若是又須要建立A則會從緩存中獲取A的工廠,調用其getObject()方法獲取其實力,並將實例對象A放入earlySingletonObjects這個緩存中,以後將對應的ObjectFactory從singletonFactories中移除。
於是getSingleton()
的邏輯就是根據beanName先從全局緩存中查找bean,沒找到再從工廠緩存查找其工廠,找到就從工廠中取出,沒找到上的話則返回null。
// 從緩存中獲取bean若緩存中不存在則從其ObjectFactory中獲取,若ObjectFactory不存在則返回null Object sharedInstance = getSingleton(beanName);
這裏咱們假設以前沒有從當前容器的緩存中找到bean,這樣比較符合初始化語境。這時候sharedInstance爲null,接着會嘗試從當前容器的父容器中去獲取
// Check if bean definition exists in this factory. //獲取父容器,嘗試從父容器中獲取 BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // Not found -> check parent. String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { //遞歸從父容器中獲取想要的bean return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null) { // Delegation to parent with explicit args. return (T) parentBeanFactory.getBean(nameToLookup, args); } else if (requiredType != null) { // No args -> delegate to standard getBean method. return parentBeanFactory.getBean(nameToLookup, requiredType); } else { return (T) parentBeanFactory.getBean(nameToLookup); } } if (!typeCheckOnly) { markBeanAsCreated(beanName); }
邏輯能夠簡化爲:獲取當前容器的父容器並遞歸調用getBean()方法進行查找
這裏有解析bean依賴的操做,原來我一直覺得這裏就是遞歸建立依賴bean的入口,但其實這裏正如註釋所言,只是爲了保證當前bean的全部依賴bean已經初始化完畢,
真正開始解析bean之間的依賴關係實際上是在後面爲bean注入屬性時,當發現bean A依賴於bean B時,會暫停A的屬性注入和初始化操做轉而去建立B。因此這部分不是很重要,瞭解下便可。
// Guarantee initialization of beans that the current bean depends on. //保證該bean全部依賴的bean已經初始化完畢 String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } //記錄與當前bean有關的依賴關係 registerDependentBean(dep, beanName); try { //先嚐試獲取該bean所依賴的bean getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } }
這裏再一次調用了getSingleton()方法,不過此次傳遞了一個實現ObjectFactory接口的匿名內部類(lambda語法簡化),
@FunctionalInterface public interface ObjectFactory<T> { /** * Return an instance (possibly shared or independent) * of the object managed by this factory. * @return the resulting instance * @throws BeansException in case of creation errors */ T getObject() throws BeansException; }
// Create bean instance. if (mbd.isSingleton()) { //走到這裏說明bean的定義是單實例的 //嘗試從全局緩存中獲取bean,若沒獲取到則經過BeanDefinition信息建立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; } }); //從FactoryBean中獲取真正的bean實例 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }
首先仍是會嘗試從全局緩存中獲取bean,若是不存在纔會調用工廠的getObject()方法去建立該bean,這個匿名內部類的getObject()方法又調用了createBean()方法,這個方法定義在AbstractBeanFactory
這個抽象工廠類中,不過具體實如今其子類AbstractAutowireCapableBeanFactory
,這個類中的createBean()纔是真正建立Bean的方法
兜兜轉轉終於來到了最重要的真正建立bean的方法,來到這個方法,說明從緩存中獲取bean的嘗試失敗,轉爲真正建立並初始化它。
//根據設置的class屬性或者根據className來解析Class Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); }
// Prepare method overrides. try { //2.對override屬性進行標記及驗證 mbdToUse.prepareMethodOverrides(); }
這裏和Spring的方法注入功能相關,Spring除了有構造器注入、屬性注入和工廠方法注入外還有方法注入
spring的bean配置中存在lookup-method和replace-method兩個配置,這兩個放在BeanDefinition的methodOverrides屬性中
若是bean實例化的時候檢測到methodOverrides屬性,會動態的爲當前bean生成動態代理並使用相關攔截器對bean作加強,
其底層經過CGLib在運行期動態操做Class字節碼實現
好比bean定義中的
方便爲單實例bean的多實例屬性注入依賴且與Spring容器沒有耦合;還有一種
的方法替換另外一個bean的方法。
這裏應該是初始化bean的流程中第一個容許用戶進行回調的擴展點。
在講解這部分源碼前先了解下一個特殊的後置處理器——InstantiationAwareBeanPostProcessor
它擴展自BeanPostProcessor
它內部定義了三個回調方法,其中比較重要的是下面這個
@Nullable default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { return null; }
在對象實例化前回調,能夠經過回調該方法返回一個代理對象來替代默認的對象實例化過程
好了能夠開始講這部分的源碼了
try { // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. //實例化bean以前的處理,會獲取全部的InstantiationAwareBeanPostProcessor,執行其回調方法 //這部分和Spring AOP相關 Object bean = resolveBeforeInstantiation(beanName, mbdToUse); //短路控制,實例化bean以前的前置處理過程返回的bean若是不爲空,則直接返回該bean if (bean != null) { return bean; } }
/** * Apply before-instantiation post-processors, resolving whether there is a * before-instantiation shortcut for the specified bean. * @param beanName the name of the bean * @param mbd the bean definition for the bean * @return the shortcut-determined bean instance, or {@code null} if none */ @Nullable protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) { Object bean = null; //還沒有被解析 if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) { // Make sure bean class is actually resolved at this point. if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { Class<?> targetType = determineTargetType(beanName, mbd); if (targetType != null) { // 執行實例化前置方法 bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName); if (bean != null) { //執行實例化後置方法 bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } } } mbd.beforeInstantiationResolved = (bean != null); } return bean; }
@Nullable protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName); if (result != null) { return result; } } } return null; }
獲取後處理器並回調的邏輯封裝在resolveBeforeInstantiation()方法中,注意這裏的返回值,若是返回值不爲null,直接return,不走後面的實例化流程了。
值得一提的是,經過Spring在這裏提供的擴展點,確實有可能返回一個代理對象,那麼Spring AOP生成的動態代理對象是這裏生成的嗎?很遺憾,一般狀況並非,除非你作了相關的自定義設置。
當resolveBeforeInstantiation)()方法返回的結果爲null,會執行後續的常規實例化操做。
try { Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isTraceEnabled()) { logger.trace("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; }
doCreateBean是實例化bean的核心方法
// Instantiate the bean. BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { //實例化bean,這裏根據BeanDefinition建立BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args); }
createBeanInstance()裏面是建立bean實例(準確來講是個bean的wrapper對象)的過程,這個過程設計兩類策略的選擇
@Override public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, final Constructor<?> ctor, Object... args) { //判斷是否有須要動態改變(lookup-method動態重寫,replace-method動態替換)的方法 if (!bd.hasMethodOverrides()) { if (System.getSecurityManager() != null) { // use own privileged to change accessibility (when security is on) AccessController.doPrivileged((PrivilegedAction<Object>) () -> { ReflectionUtils.makeAccessible(ctor); return null; }); } //不存在須要動態改變的方法,直接使用反射建立對象 return BeanUtils.instantiateClass(ctor, args); } else { //存在須要動態改變的方法,使用cglib生成子類的方式動態替換原有方法 return instantiateWithMethodInjection(bd, beanName, owner, ctor, args); } }
以前只是建立了一個空的bean,爲bean的屬性進行賦值經過下面的方法完成
populateBean(beanName, mbd, instanceWrapper);
整個過程能夠分爲4步:
//調用InstantiationAwareBeanPostProcessor的實例化後置處理方法 if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { //其中一個處理器的回調方法返回false,則跳出循環 continueWithPropertyPopulation = false; break; } } } } if (!continueWithPropertyPopulation) { //不執行後續的屬性填充操做,直接返回 return; }
//根據名稱或者類型進行依賴注入 if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues(pvs); // Add property values based on autowire by name if applicable. //按名稱進行依賴注入 if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } // Add property values based on autowire by type if applicable. //按類型進行依賴注入 if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) { autowireByType(beanName, mbd, bw, newPvs); } pvs = newPvs; }
這裏嘗試爲bean注入依賴,能夠按名稱或者按類型進行注入。這裏纔是真正開始進行依賴解析並遞歸建立bean的地方,以autowireByName()爲入口一探究竟
1處開始遞歸建立依賴的bean
2處則是講與當前bean有關的依賴關係進行註冊,主要是填充兩個map
public void registerDependentBean(String beanName, String dependentBeanName) { String canonicalName = canonicalName(beanName); //dependentBeanMap<String(beanName),Set<String>(依賴於前者的全部beanName集合)> synchronized (this.dependentBeanMap) { Set<String> dependentBeans = this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8)); if (!dependentBeans.add(dependentBeanName)) { //已經存在 return; } } //dependenciesForBeanMap<String(beanName), Set<String>(被前者依賴的全部beanName集合)> synchronized (this.dependenciesForBeanMap) { Set<String> dependenciesForBean = this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8)); dependenciesForBean.add(canonicalName); } }
dependentBeanMap:value爲依賴於當前bean的全部bean的beanName集合
dependenciesForBeanMap:value爲當前bean所依賴的全部bean的beanName集合
for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { if (filteredPds == null) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { return; } } pvs = pvsToUse; } }
if (pvs != null) { applyPropertyValues(beanName, mbd, bw, pvs); }
這步執行完畢,bean的全部依賴就都已經注入,全部屬性都已經填充完畢了
exposedObject = initializeBean(beanName, exposedObject, mbd);
private void invokeAwareMethods(final String beanName, final Object bean) { if (bean instanceof Aware) { if (bean instanceof BeanNameAware) { ((BeanNameAware) bean).setBeanName(beanName); } if (bean instanceof BeanClassLoaderAware) { ClassLoader bcl = getBeanClassLoader(); if (bcl != null) { ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl); } } if (bean instanceof BeanFactoryAware) { ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); } } }
@Override public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { //回調其初始化前置方法 Object current = processor.postProcessBeforeInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }
這裏的初始化方法有兩種,一種是用戶在定義bean時配置的init-method,一種是InitialLizingBean接口的的afterProperties()方法
@Override public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { //回調初始化後置方法 Object current = processor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }
到這裏基本上IOC容器建立bean的流程就結束了,只有還有一些可有可無的內容,就不貼源碼了。
原本還但願容器初始化單實例bean這部份內容可以講的簡單清晰,主次分明些,想不到仍是寫成了流水帳,惟一值得欣慰的地方大概是終於把容器啓動流程中最複雜也是最重要的階段——初始化單實例bean的過程好好梳理了一遍,想繼續探討AOP源碼的話也能找到切入點了。最後如下面這張圖做爲總結吧,基本理清了容器實例化bean的過程以及解決循環依賴的思路。
假設要建立的bean A和B之間存在循環依賴,整個過程以下圖所示
《spring源碼深度解析》