Spring核心源碼深度解析(六)實例化和初始化對象

?Spring 創建對象

在上一章我們對invokeBeanFactoryPostProcessors的重要部分進行了詳細的介紹,總算到了我們的Spring創建對象的過程了,本章會接著前面的refresh進行續寫。

registerBeanPostProcessors(beanFactory)

這個方法的特性和invokeBeanFactoryPostProcessors(beanFactory);其實差不太多,也是對后置處理器的一些操作,但這個方法的重量缺少了很多,相信讀者有了invokeBeanFactoryPostProcessors(beanFactory);的經驗應該能夠自行理解其基本意義。

initMessageSource();

初始化國際化資源,這里只是對一些資源加載的方式進行規范。

initApplicationEventMulticaster();

創建ApplicationEventMulticaster這么一個類,這個類是事件操控的核心,我們先跳過,這里不會影響整體Bean初始化

onRefresh();

空方法

registerListeners

注冊監聽器

finishBeanFactoryInitialization(beanFactory)

總算到我們真正創建Bean的核心方法了,通過這個方法的名字就可以猜到,這就是我們Spring用來創建對象的核心方法,如果不相信的話我們在這里調試一下,首先看第一張圖


image

singletonObjects就是我們的實例對象,這里不同的Spring版本可能singletonObjects所在的類會有一些區別,那么如果singletonObjects數量發生改變說創建對象就是在這里實現的,我們調試一下


image
image

可以看到singletonObjects的數量確實增加了幾個,而且這幾個就是我們所創建的,那么我們就開始對其進行分析,在對finishBeanFactoryInitialization深度分析時,筆者只會對一些核心點進行解釋說明,因為內容確實太多,有些比較特殊的我就一筆帶過,話不多說看代碼

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // 這里不知道CONVERSION_SERVICE_BEAN_NAME有什么用
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
        beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
      beanFactory.setConversionService(
          beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    }
?
    // Register a default embedded value resolver if no bean post-processor
    // (such as a PropertyPlaceholderConfigurer bean) registered any before:
    // at this point, primarily for resolution in annotation attribute values.
    //檢查Spring中是否存在類型轉換
    if (!beanFactory.hasEmbeddedValueResolver()) {
      beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
    }
    // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
      getBean(weaverAwareName);
    }
?
    // 禁止使用臨時類加載器進行類型匹配
    beanFactory.setTempClassLoader(null);
?
    // Allow for caching all bean definition metadata, not expecting further changes.
    //允許緩存所有的bean的定義數據
    beanFactory.freezeConfiguration();
?
    // Instantiate all remaining (non-lazy-init) singletons.
    //重點,準備bean實例
    beanFactory.preInstantiateSingletons();
  }

注釋比較詳細,這里其實沒做什么事情,核心方法是beanFactory.preInstantiateSingletons();我們點進去

  public void preInstantiateSingletons() throws BeansException {
    if (logger.isTraceEnabled()) {
      logger.trace("Pre-instantiating singletons in " + this);
    }
    // Iterate over a copy to allow for init methods which in turn register new bean definitions.
    // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
    //拿到所有的bd名字
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
?
    // Trigger initialization of all non-lazy singleton beans...
    //循環并判斷是不是不是懶加載的,是不是FactoryBean,然后對bd進行bean創建
    for (String beanName : beanNames) {
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
        if (isFactoryBean(beanName)) {
          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) {
              getBean(beanName);
            }
          }
        }
        else {
          getBean(beanName);
        }
      }
    }
?
    // Trigger post-initialization callback for all applicable beans...
    for (String beanName : beanNames) {
      Object singletonInstance = getSingleton(beanName);
      if (singletonInstance instanceof SmartInitializingSingleton) {
        final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
        if (System.getSecurityManager() != null) {
          AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            smartSingleton.afterSingletonsInstantiated();
            return null;
          }, getAccessControlContext());
        }
        else {
          smartSingleton.afterSingletonsInstantiated();
        }
      }
    }
  }

這里首先執行RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);將我們的BeanDefinition合并,最后都采用RootBeanDefinition聲明,然后判斷是不是單例對象,是不是FactoryBean,如果不是就會進入getBean(beanName);我們在跟進


image

這里為什么是GetBean而不是創建對象,其實 Spring在很多地方都會獲取對象,所以不可能每次獲取都是創建對象,而應該是先查詢有沒有,再創建就像我們使用的緩存技術一樣。我們繼續


image

進入這句代碼:Object sharedInstance = getSingleton(beanName);


image

這里先簡單分析下,如果獲取的對象是沒有完全創建的,那么的singletonObject為空,isSingletonCurrentlyInCreation(beanName)也會為false那么判斷會退出,記住這個isSingletonCurrentlyInCreation,然后我們繼續


image

這些都不重要,我們往下看----

Bean實例化

image

這里的return createBean(beanName, mbd, args);是表達式語法,其實就是一個回調方式,然后我們調試進入getSingleton,


image

這里會做一些判斷,如果沒有實例化這個對象那么
它就會執行這段代碼beforeSingletonCreation(beanName);我們看看這段代碼做了什么


image

他會將我們的對象標識為正在創建,記住這個標識


image

然后再往下走回走到singletonObject = singletonFactory.getObject();


image

可以看到這里產生回調,不熟悉函數式的朋友們可以先忽略它,我們進入createBean(beanName, mbd, args);


image
image

前面都不重要,可以看到創建對象的代碼在這一行Object beanInstance =

doCreateBean(beanName, mbdToUse, args);筆者這里再啰嗦一下這段代碼Object bean =resolveBeforeInstantiation(beanName, mbdToUse);
image

這里筆者認為設計的有些累贅了,它的目的其實就是如果程序員定義的對象實現這個InstantiationAwareBeanPostProcessor接口,那么Spring就會認為這個對象不需要經過Spring的完整生命周期,需要脫離Spring管理的意思,然后直接return掉,但我想Spring可能也是為了擴展的開放性吧,畢竟Spring的設計考慮的十分周全。好了,我們回到代碼Object beanInstance = doCreateBean(beanName, mbdToUse, args);


image

這里定義了一個instanceWrapper,讀者可以將其當做一個有一些功能的對象,然后進入instanceWrapper = createBeanInstance(beanName, mbd, args);


image

這里主要是獲取class類型,然后判斷是不是FactoryMethod創建對象,如果不是就繼續往下:


image

這里其實是一種緩存技術,如果我們在前面已經確認了這個類的構造器是什么,那么久不會再進行下文的構造器策略,直接調用構造器方法,當然我們這里暫時沒有。


image

這里是Spring對實例構造器的一個策略,我們都知道一個類創建一個對象無非就兩種情況,調用有參構造函數或者無參構造函數,那么我們先從無參構造說起,看下圖


image

假如我們的ctors為空 也就是說我們的對象是用的無參構造,那么會執行到return instantiateBean(beanName, mbd);,我們跟蹤此代碼


image

在跟蹤beanInstance =getInstantiationStrategy().instantiate(mbd, beanName, parent);->return BeanUtils.instantiateClass(constructorToUse);->


image

最終可以看到我們的反射代碼newInstance。介紹完無參構造器創建對象后,我們開始探討第二種有參構造創建對象的方式,回到IDEA,首先我們對User1類新增一個有參構造器,


image

然后我們開始debug調試,我們以User1類作為調試類


image

然后進入determineConstructorsFromBeanPostProcessors方法


image

這里會拿出很多后置處理器,但前面的基本都是默認實現,真正干活的是這個類AutowiredAnnotationBeanPostProcessor
然后進入:


image

前面的方法是檢查是否存在LOCKUP方法,我們這里沒有執行下一步


image

這里也沒做什么事情,只是想從緩存中拿出有沒有確定好的構造器,后面會獲取所有構造方法,判斷方法是不是加了@Awtowire注解,基本都會跳過,我們直接跳到核心代碼


image

這里其實就是確認構造器,從我們的斷點來看,當我們拿到的構造函數只有一個,且參數大于0,從我們目前的情況來看是符合的,那么就會返回我們構造器。拿到構造器后我們再看


image

我們會拿到我們所創建的構造器,那如果我們換一種方式采用多個構造器


image

我們調試發現
image

返回的值為null,其實這也很好理解,在沒有指定某個構造器primary時,如果我們創建多個構造器,Spring不知道如何決策,就只執行默認構造器


image

,在上文我們對無參構造的方式進行了介紹,現在我們對有參構造進行說明
image

autowireConstructor()->autowireConstructor();
這里我們思考下如何用有參構造的方式創建對象,首先是不是確定我們的類,其次是不是需要確定構造器,然后我們還需要確定參數的值是什么,那么下面的操作就是確定參數的值到底是什么,我們回到IDEA:


image

這里沒什么需要多說的


image

這里看有沒有緩存,顯然我們沒有


image

這里的代碼個人認為Spring可能為了防止其他地方復用這段代碼,所以判斷構造器是不是為空


image

這里autowiring肯定不會false,然后進入有參構造十分關鍵的代碼


image

通過方法名我們都能大概猜出來這里就是獲取有參構造傳入的參數值,前面我們說過,確定構造器還需要構造參數的值才能成功創建一個對象,那么我們看這個代碼能否獲取參數值


image

很顯然這里并沒有獲取,道理很簡單,因為我們并沒有對User1類指定構造器參數值,如果我們繼續運行下去,Spring會拋出異常,表示無法創建這個類,這樣很好說明,我們想要使用有參構造創建對象,確定沒有給定參數值,這必然會報錯,
image

那么怎樣才能獲取參數值呢,這里筆者會采用兩種方式:第一種方式筆者會改變Spring源碼


image

然后我們再次運行
image

,發現已經有值,然后User1類會創建對象成功,當然我們去改變源碼是不是不太合適啊,所以采用第二種方式后置處理器,代碼如下:


image

依舊可以實現有參構造的方式,

讀到這里,讀者是否有些恍然大悟,領略到了筆者前面提出的Spring的后置處理器的作用和設計的精妙,這樣就可以實例化一個對象了,當然這還沒有完,Spring還會對其他特別的有參構造進行解析,因為設計思想較為復雜,讀者有興趣可以自行深入了解,那么我們的對象實例化就算結束了,回到IDEA,
image

這里我們返回了我們的對象。

Bean初始化

image

在創建完對象后,Spring將會對象進行初始化,我們跟蹤applyMergedBeanDefinitionPostProcessors這段代碼:


image

可以看到這又是循環后置處理器,獲取屬于MergedBeanDefinitionPostProcessor,然后我們繼續跟蹤bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);在查看這個方法到底會執行哪些處理器,


image

我們在對其中之一后置處理器點開


image
image

其實這里的處理器就是對我們Spring的生命周期的處理,但這里并不會執行,而是采用元信息的方式將它保存起來,好了,我們繼續往下看


image

前面的代碼不重要,我們直接看到addSingletonFactory(beanName, () ->
getEarlyBeanReference(beanName, mbd, bean));


image

這里會有四個集合,第一個集合是singletonObjects存放單例Bean的,第二個singletonFactories
存放的是ObjectFactory工廠Bean,這個ObjectFactory個人認為和Bean并無太大區別,直接間接存取而已,第三個earlySingletonObjects是提前存儲的對象,最后一個registeredSingletons存放的是BeanName,用來解決排序問題,好了我們繼續


image

接下來可以看到Spring的屬性注入的核心代碼populateBean(beanName, mbd,
instanceWrapper);,在對這段代碼分析之前,我們先修改一下我們的工程,首先將User2改成


image

再將User1改成
image

這條調整的目的是為了演示循環依賴,好了,
然后我們重新debug


image

這里先對User1屬性注入,我們點進去


image

這里又有對后置處理器的處理,這里后置處理器的作用是如果你實現了InstantiationAwareBeanPostProcessors的postProcessAfterInstantiation方法,那么Spring會認為你牛逼,你要自己初始化,那我就中斷這個Bean的后續一切操作,就等于脫離Spring的生命周期管理,其實這也是可以想到的,不一定所有的對象都是需要Spring幫我們處理,這里Spring的設計考慮的十分周全,我們回到IDEA


image

這里有一個重要的屬性叫AutowireMode,為什么說他重要,我們會在Spring-Mybatis章節詳細說明,這里先跳過,因為我們默認的是NO,然后我們進入這里


image

看方法名能夠大概猜到這里就是屬性注入的關鍵,我們斷點


image

然后我們直接跳到AutowiredAnnotationBeanPostProcessor,進入這個方法PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);首先獲取我們的InjectionMetadata,注入需要的元數據


image

然后->metadata.inject(bean, beanName, pvs);->element.inject(target, beanName, pvs);

然后我們先看最后一行代碼
image

field.set(bean, value);懂反射的小伙伴們都知道,我們可以通過Field類對一個類的對象屬性賦值,所以Spring默認也采用的這種方式,那么我們現在有了類,缺少value,而這個value在元數據中已經顯示User2類,所以我們需要拿到User2的對象才行,回到IDEA上面的代碼,其中有一行


image

然后我們跟蹤下resolveDependency->doResolveDependency->descriptor.resolveCandidate


image

最終又回到了getBean,也就是說Spring會從工廠里拿,而這個時候我們的工廠并沒有創建它,所以User2創建對象后依舊會進行進入屬性注入的方法


image

這個時候我們跳到了User2的屬性注入方法,然后一樣User2里面有User1這個類,所以又會去獲取User1的對象,但是我們的User1并沒有創建完成,屬于創建中的狀態,那么Spring是如何解決的呢?我們繼續跟蹤代碼


image

這里的代碼是我們先創建了User1然后屬性注入user2,這時工廠沒有User2對象,于是創建User2,User2創建完后開始對內部的屬性user1注入,這時會跳到上圖,然后我們再跟蹤進去


image

singletonObject == null 目前是為空的,因為我們的user1還在創建中,然而這一行代碼我們運行isSingletonCurrentlyInCreation(beanName)


image

返回的是true,還記我們創建對象時會將對象標識為正在創建嗎?這里就起到了效果,那么if會成立,這個時候就會從我們的ObjectFactory獲取,在上文提到過ObjectFactory是間接存取,


image

隨后User2拿到了User1的對象,然后User1也會拿到User2的對象因此解除循環依賴,創建對象成功,最后
image

這里會獲取我們前文存儲的生命周期元數據,并執行


image
image

我們用一張圖回顧下我們的循環依賴


image

目前對Spring的整體核心源碼基本已經告一段落,后面會對AOP、Spring-Mybatis、事物、數據來源、事件等知識結合面試題的方式進行嵌套描述。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。