Spring源碼分析:@Autowired註解原理分析

前言

關於@Autowired這個註解,咱們再熟悉不過了,常常跟@Resource來作對比,這篇文章咱們不討論二者有何異同,僅分析@Autowired的原理(基於Spring5)。java

問題

假如一個接口(IUserService)有兩個實現類,分別是(UserServiceImpl01)和(UserServiceImpl02),在咱們給類注入的時候,這樣寫(@Autowired private IUserService userService)會發生什麼狀況?答案確定是報錯,那麼原理呢?文字描述:由於首先@Autowired是按照類型注入的,也就是.class,但UserServiceImpl01和UserServiceImpl02都是IUserService類型的,因而Spring就會按照後面的名字(userService)在容器中查找,但發現根本沒有這個名字,由於兩個實現類在不指定名字狀況下,就是首字母小寫的類名,而後拋出異常:expected single matching bean but found 2。。。app

如何解決這類問題

  1. 若是有兩個實現類,還要使用@Autowired註解,能夠將userService改爲咱們指定的實現類名稱,好比UserServiceImpl01,或者不想改userService,能夠加@Qualifier(value = "userServiceImpl01"),指定須要注入的實現類。
  2. 使用@Resource註解,手動指定實現類名稱。

還有不少種方法,但基本思想都同樣,無非就是如何區分兩個同祖宗的兒子,既然根兒相同,那就只有指定名字了。源碼分析

@Autowired原理

提到@Autowired咱們通常都知道叫依賴注入post

  1. 什麼是依賴注入?
  2. 什麼是注入,注到哪裏?
  3. 何時注入的?

什麼是依賴注入?

依賴注入:Dependency Injection,簡稱DI,說白了就是利用反射機制爲類的屬性賦值的操做。this

什麼是注入,注入到哪裏?

注入就是爲某個對象的外部資源賦值,注入某個對象所須要的外部資源(包括對象、資源、常量數據等)。IOC容器注入應用程序某個對象,應用程序所依賴的對象。spa

何時注入的?

在完成對象的建立,爲對象變量進行賦值的時候進行注入(populate)。debug

源碼分析

  1. 首先點開@Autowired,註釋上寫Please consult the javadoc for the AutowiredAnnotationBeanPostProcessor,讓咱們去查閱這個類,看一下這個類的繼承關係樹,以下:

請輸入圖片描述
可見它間接實現InstantiationAwareBeanPostProcessor,就具有了實例化先後(而不是初始化先後)管理對象的能力,實現了BeanPostProcessor,具備初始化先後管理對象的能力,實現BeanFactoryAware,具有隨時拿到BeanFactory的能力,也就是說,這個AutowiredAnnotationBeanPostProcessor具有一切後置處理器的能力。對象

  1. 容器在初始化的時候,後置處理器的初始化要優先於剩下自定義Bean(好比咱們自定義的Service,Controller等等)的初始化的,咱們自定義的Bean初始化是在finishBeanFactoryInitialization(beanFactory)這裏完成的,來到AbstractApplicationContext的refresh()方法。
  2. finishBeanFactoryInitialization(beanFactory)-->beanFactory.preInstantiateSingletons()-->getBean(beanName)-->doGetBean(beanName)-->來到AbstractBeanFactory第317行createBean(beanName, mbd, args),來建立bean實例-->來到AbstractAutowireCapableBeanFactory第503行doCreateBean(beanName, mbdToUse, args)-->緊接着來到AbstractAutowireCapableBeanFactory的第543行,instanceWrapper = createBeanInstance(beanName, mbd, args)就已經把Bean實例建立出來了,只不過instanceWrapper是一個被包裝過了的bean,它裏面的屬性還未賦實際值-->而後來到第555行applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName),這一步的做用就是將全部的後置處理器拿出來,而且把名字叫beanName的類中的變量都封裝到InjectionMetadata的injectedElements集合裏面,目的是之後從中獲取,挨個建立實例,經過反射注入到相應類中。

請輸入圖片描述

  1. 緊接着來到AbstractAutowireCapableBeanFactory第588行populateBean(beanName, mbd, instanceWrapper)-->點進去,來到AbstractAutowireCapableBeanFactory的第1347行,來循環遍歷全部的後置處理器for (BeanPostProcessor bp : getBeanPostProcessors()),從方法名字postProcessPropertyValues也能看出來,就是給屬性賦值,當bp是AutowiredAnnotationBeanPostProcessor的時候,進入postProcessPropertyValues方法,來到AutowiredAnnotationBeanPostProcessor的postProcessPropertyValues方法,以下:

請輸入圖片描述
首先找到須要注入的哪些元數據,而後metadata.inject(注入),注入方法點進去,來到InjectionMetadata的inject方法,在一個for循環裏面依次執行element.inject(target, beanName, pvs),來對屬性進行注入。blog

  1. 進入element.inject(target, beanName, pvs),注意,這裏必需要debug才能夠進入真正的方法。來到AutowiredAnnotationBeanPostProcessor的inject方法,

第584行,value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter),由工廠解析這個依賴,進入,來到DefaultListableBeanFactory第1065行,result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter)再次解析依賴,點擊進入,來到DefaultListableBeanFactory的doResolveDependency()方法,前面是一堆判斷,比較,查看屬性類型,這種類型的有幾個(matchingBeans),若是隻有一個匹配,那麼來到第1138行,instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this),進入這個方法,能夠看到就是前面說的根據工廠來建立實例的過程了:beanFactory.getBean(beanName),其中這個beanName就是屬性的名稱,當通過一系列操做完成屬性的實例化後,便來到AutowiredAnnotationBeanPostProcessor的第611行,利用反射爲此對象賦值。這樣,對象的建立以及賦值就完成了。繼承

總結

在容器啓動,爲對象賦值的時候,遇到@Autowired註解,會用後置處理器機制,來建立屬性的實例,而後再利用反射機制,將實例化好的屬性,賦值給對象上,這就是Autowired的原理。

相關文章
相關標籤/搜索