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


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

前言

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

問題

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

如何解決這類問題

  1. 如果有兩個實現類,還要使用@Autowired注解,可以將userService改成我們指定的實現類名稱,比如UserServiceImpl01,或者不想改userService,可以加@Qualifier(value = "userServiceImpl01"),指定需要注入的實現類。
  2. 使用@Resource注解,手動指定實現類名稱。

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

@Autowired原理

提到@Autowired我們一般都知道叫依賴注入

  1. 什么是依賴注入?
  2. 什么是注入,注到哪里?
  3. 什么時候注入的?

什么是依賴注入?

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

什么是注入,注入到哪里?

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

什么時候注入的?

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

源碼分析

  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),來對屬性進行注入。

  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的原理。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM