1. 程式人生 > >ioc註解原理詳解

ioc註解原理詳解

  • 一、@Autowired

        作為一個spring開發者對@Autowired註解必定是非常瞭解了, 顧名思義自動裝配,應該是Spring會自動將我們標記為@Autowired的元素裝配好,與其猜測不如看看它的定義:

  • @Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD,  
  •                          ElementType.ANNOTATION_TYPE})  
  • @Retention(RetentionPolicy.RUNTIME)  
  • @Documented  
  • public @interface Autowired {  
  •     boolean required() default true;  
  • }  
  •  很明顯這個註解可以用到構造器,變數域,方法,註解型別上。文件上這樣描述:將一個構造器,變數域,setter方法,config方法標記為被Spring DI 工具自動裝配。換句話說,我們檢視從bean 工廠中獲取一個bean時,Spring會自動為我們裝配該bean中標記為@Autowired的元素,而無需我們手動完成。這些相信大家都明白,但問題是,Spring是怎樣做到的?在Spring MVC中怎樣做到的?什麼時候進行的自動裝配?下面我們就來探究下這些問題。

    二、BeanPostProcessor

        在@Autowired的定義中有下面一段話:

  • <pre name="code" class="java">Note that actual injection is performed through a BeanPostProcessor   
  • which in turn means that you cannot use @Autowired to inject references into BeanPostProcessor  
  • or BeanFactoryPostProcessor types.   
  • Please consult the javadoc for the AutowiredAnnotationBeanPostProcessor class   
  • (which, by default, checks for the presence of this annotation).  
  • 意思是:實際的注入裝配動作是由BeanPostProcessor執行的,翻過來說你不能將@Autowired註解用於BeanPostProcessor或BeanFactoryPostProcessor型別上。請檢視AutowiredAnnotationBeanPostProcessor文件(預設情況下,被用來檢查@Autowired註解)。

        文件說的很清楚了,BeanPostProcessor來執行自動裝配,並且預設情況下使用AutowiredAnnotationBeanPostProcessor實現類完成。那我們不妨看一下他們的定義:

    ?

    [java] view plain copy
    1. public interface BeanPostProcessor {  
    2.     Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;  
    3.     Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;  
    4. }  

       BeanPostProcessor就一個回撥介面,定義了兩個方法宣告,一個是例項化前被呼叫,一個是例項化後被呼叫,沒啥好看的,我們直接看看它的實現類AutowiredAnnotationBeanPostProcessor:

    [java] view plain copy
    1. BeanPostProcessor implementation that autowires annotated fields, setter methods and arbitrary   
    2. config methods. Such members to be injected are detected through a Java 5 annotation:   
    3. by default, Spring's @Autowired and @Value annotations.Also supports JSR-330's @Inject   
    4. annotation, if available, as a direct alternative to Spring's own @Autowired.  
    5. Note: A default AutowiredAnnotationBeanPostProcessor will be registered by   
    6. the "context:annotation-config" and "context:component-scan" XML tags.  
    7. NOTE: Annotation injection will be performed before XML   
    8. injection; thus the latter configuration will override the former for properties   
    9. wired through both approaches.  

       上面是AutowiredAnnotationBeanPostProcessor類的描述文件摘要,大致意思是:這是BeanPostProcessor介面的一個實現,用來自動裝配註解的變數域,setter方法和任意的config方法。這些被注入的元素是通過檢測Java 5的註解完成的:預設情況下是@Autowired和@Value註解。同樣也支援JSR-330的@Inject註解。並且,<context:annotation-config/>和<context:component-scan/>XML標籤可以預設註冊AutowiredAnnotationBeanPostProcessor到bean工廠中。最後,註解注入會在XML注入之前執行;因此後面的配置會覆蓋前面已經裝配好的元素。

        是不是很清楚了?Spring的文件總是這麼詳細,要麼說是教科書呢,廢話不多說,我們才剛進正題呢,既然我們清楚了是AutowiredAnnotationBeanPostProcessor例項執行了自動裝配,那麼它做了什麼呢?

    三、磨刀砍柴    

    在正式檢視原始碼前,我先大致的講一下整個裝配的過程,以便後面理解起來輕鬆些。其實整體思路還是很簡單的,我們舉個簡單的例子:

  • //==================================Controller  
  • @Controller  
  • public class SimpleController {  
  •     @Autowired  
  •     private SimpleService simpleService;  
  • }  
  • //==================================Service  
  • @Service("simpleService")  
  • public class SimpleServiceImpl implements SimpleService {  
  •     @Autowired  
  •     private SimpleDao simpleDao;  
  • }  
  • //===================================Repository  
  • @Repository("simpleDao")  
  • public class SimpleDaoImpl implements SimpleDao {  
  • }  
  • 1)在某一時刻Spring呼叫了 Bean工廠 的 getBean(beanName) 方法。beanName可能是simpleController,或者simpleService,simpleDao,順序沒關係(因為後面會有依賴關係的處理)。我們假設simpleController吧。

    2)getBean方法首先會呼叫Bean工廠中定義的getSingleton(beanName)方法,來判斷是否存在該名字的bean單例,若果存在則返回,方法呼叫結束。

    3)否則,Spring會檢查是否存在父工廠,如果有則返回,方法呼叫結束。

    4)否則,Spring 會檢查該bean 定義(BeanDefinition例項,用來描述Bean結構,上篇文章講到過,component-scan 掃描後,就是將beanDefinition例項放入Bean工廠,此時Bean還沒有被例項化。)是否有依賴關係,如果有,執行1)步,獲取依賴的bean例項。

    5)否則,Spring會嘗試建立這個bean例項,建立例項前,Spring會檢查確定呼叫的構造器,並例項化該Bean。

    6)例項化完成後,Spring會呼叫Bean工廠的populateBean方法來填充bean例項的屬性,也就是我們前面提到的自動轉配了。populateBean方法便是呼叫了BeanPostProcessor例項來完成屬性元素的自動裝配工作。

    7)在元素裝配過程中,Spring會檢查被裝配的屬性是否存在自動裝配的其他屬性,然後遞迴呼叫getBean方法,直到所有@Autowired的元素都被裝配完成。如在裝配simpleController中的simpleService屬性時,發現SimpleServiceImpl例項中存在@Autowired屬性simpleDao,然後呼叫getBean(simpleDao)方法,同樣會執行1)-7)整個過程。所以可以看成一個遞迴過程。

    8)裝配完成後,Bean工廠會將所有的bean例項都新增到工廠中來。

    注:我們知道Spring MVC是多執行緒單例項的MVC框架,就是說,對於同一個Controller,只會生成一個例項來處理所有的請求,因此bean例項只會例項化一次,並被存放在工廠中,以供其他請求使用。

    好了,大致瞭解整個流程後我們看一下Spring的具體行為吧。

    四、Bean 工廠

        前面多次提到了Bean工廠,但一直沒有說它到底是個什麼,這裡我們就徹底弄清楚吧,省的雲裡霧裡,這樣我們後面講到Bean工廠就不會暈了。看過上一篇部落格(<context:component-scan/>)的朋友可能記得DefaultListableBeanFactory這個類,當時是它儲存了掃描到的元件--Bean Definition例項。那他是否是我們所說的Bean工廠呢?是否儲存了Bean例項呢?答案是:對。

    我們可以看到DefaultLiableBeanFactory繼承自DefaultSingletonBeanRegistry,AbstractBeanFactory,AbstractAutowireCapableBeanFactory。下面就列出了一下相關的Bean工廠中的屬性和方法:

    [java] view plain copy
    1. //==========================================================================================  
    2. //==============================DefaultListableBeanFactory================================  
    3. //==========================================================================================  
    4. //beanName-beanDefinition 的對映表  
    5. private final Map<String, BeanDefinition> beanDefinitionMap =   
    6.                                             new ConcurrentHashMap<String, BeanDefinition>(64);  
    7. //beanName 列表  
    8. private final List<String> beanDefinitionNames = new ArrayList<String>();  
    9. //==========================================================================================  
    10. //=============================AbstractBeanFactory=================================  
    11. //==========================================================================================  
    12. //註冊了所有的BeanPostProcessor例項,包括前面提到的用來處理@Autowired註解的  
    13. //AutowiredAnnotationBeanPostProcessor   
    14. private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();  
    15. //可能存在的父親Bean工廠  
    16. private BeanFactory parentBeanFactory;  
    17. //==========================================================================================  
    18. //==============================DefaultSingletonBeanRegistry================================  
    19. //==========================================================================================  
    20. //beanName--bean單例的對映表  
    21. private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);  
    22. //註冊過的beanName集合  
    23. private final Set<String> registeredSingletons = new LinkedHashSet<String>(64);  
    24. //beanName與該bean所依賴的Beans集合的對映表,如simpleDao依賴與simpleService,如果還有其他  
    25. service使用該Dao,如simpleService2那麼是simpleDao->[simpleService,simpleService2]  
    26. private final Map<String, Set<String>> dependentBeanMap   
    27.                                             = new ConcurrentHashMap<String, Set<String>>(64);  
    28. //恰好與上面相反,beanName與該bean所包含的beans的集合對映表,如simpleController->[simpleService]  
    29. private final Map<String, Set<String>> dependenciesForBeanMap   
    30.                                             = new ConcurrentHashMap<String, Set<String>>(64);  

       可以看到Bean工廠中即存有bean definition的對映表,也存有bean name的別表,以及bean例項的對映表,還有依賴關係圖。理解了這個對下面的例項化以及裝配過程會有很大幫助。

    五,例項化與裝配

      下面我們就從頭到尾看一下整個的例項化和裝配過程:

  • public Object getBean(String name) throws BeansException {  
  •     return doGetBean(name, null, null, false);  
  • }  
  • @SuppressWarnings("unchecked")  
  • protected <T> T doGetBean(final String name, final Class<T> requiredType,   
  •                           final Object[] args, boolean typeCheckOnly)throws BeansException {  
  •         //去掉工廠bean的字首或者將別名轉化為規範名  
  •         final String beanName = transformedBeanName(name);  
  •         Object bean;  
  •         // 檢查是否有已經註冊的bean例項  
  •         Object sharedInstance = getSingleton(beanName);  
  •         if (sharedInstance != null && args == null) {  
  •             //如果是工廠bean,獲取工廠bean建立的bean  
  •             bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);  
  •         }  
  •         else {  
  •             //判斷是否有父工廠,並且其中是否存在該bean例項?  
  •             BeanFactory parentBeanFactory = getParentBeanFactory();  
  •             if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {  
  •                 String nameToLookup = originalBeanName(name);  
  •                 if (args != null) {  
  •                     return (T) parentBeanFactory.getBean(nameToLookup, args);  
  •                 }  
  •                 else {  
  •                     return parentBeanFactory.getBean(nameToLookup, requiredType);  
  •                 }  
  •             }  
  •             if (!typeCheckOnly) {  
  •                 markBeanAsCreated(beanName);//將該beanName標記為已經例項化  
  •             }  
  •             //獲取該beanName對應的BeanDefinition例項,從上面說到的beanDefinitionMap表中查詢  
  •             final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);  
  •             checkMergedBeanDefinition(mbd, beanName, args);  
  •             //判斷是否有依賴bean  
  •             String[] dependsOn = mbd.getDependsOn();  
  •             if (dependsOn != null) {  
  •                 for (String dependsOnBean : dependsOn) {  
  •                     getBean(dependsOnBean);//如果有依賴bean,遞迴呼叫getBean方法  
  •                     registerDependentBean(dependsOnBean, beanName);//將依賴關係儲存到 上面提到的  
  •                     //dependBeanMap和dependencyForBeanMap中。  
  •                 }  
  •             }  
  •             // 真正的開始床架bean例項了。激動吧  
  •             if (mbd.isSingleton()) {//beanDefinition中指定該例項為單例  
  •                 //去工廠中獲取單例,如果沒有建立一個,然後新增到工廠中,否則直接返回  
  •                 sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {  
  •                     public Object getObject() throws BeansException {  
  •                         try {  
  •                             return createBean(beanName, mbd, args);  
  •                         }  
  •                     }  
  •                 });  
  •                 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);  
  •             }  
  •             else if (mbd.isPrototype()) {//原型方式,每次都建立一個新的例項  
  •                 Object prototypeInstance = null;  
  •                 try {  
  •                     beforePrototypeCreation(beanName);  
  •                     prototypeInstance = createBean(beanName, mbd, args);  
  •                 }  
  •                 finally {  
  •                     afterPrototypeCreation(beanName);  
  •                 }  
  •                 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);  
  •             }  
  •             else {//其他方式,如目前主體無關,不贅述  
  •             }  
  •         }  
  •         return (T) bean;  
  •     }  
  •    這個方法好長,真的好長,我還刪除了一些與當前主體無關的程式碼呢,好吧,不要被嚇住,如果是自己寫的程式碼,再長都很容易弄懂,類的繼承關係再複雜都能輕車熟路,那是因為我們都清楚的知道每一行的用意,看別人的程式碼一樣,多看幾遍就明白了,再複雜都一樣。

        首先Spring會檢查beanName,獲取規範的beanName,然後它會檢查是否存在已經註冊的單例(查詢上面提到的singletonObjects對映表),如果有的話就直接返回了,一切就結束了,否則的話,會檢視是否存在父工廠,如果有呼叫父工廠的getBean方法,如果沒有呢?

        好吧那就要著手建立例項了,首先檢視beanDefinitionMap查詢該beanName對應的beanDefinition例項,然後根據該例項判斷是否存在依賴關係,如果存在在遞迴的呼叫getBean方法,直到所有的依賴關係都正確的例項化和裝配完成,並且將這些依賴關係儲存到上面提到的dependencyForBeanMap 和dependentBeanMap中。

        接下來,Spring檢視BeanDefinition來確定該Bean應該是單例方式建立還是原型方式建立?如果是單例的話,Spring會呼叫getSingleton方法查詢或建立一個單例(下面會詳聊),如果是原型的話,每次呼叫getBean方法都會建立一個新的例項,看上面程式碼便會一清二楚了。

    那下面我們就看看這個getSingleton方法做了什麼?

    ?

    6

    [java] view plain copy
    1. public Object getSingleton(String beanName, ObjectFactory singletonFactory) {  
    2.         //這不就是上面說的bean例項對映表嗎?哈,被同步了,保證執行緒安全啊  
    3.         synchronized (this.singletonObjects) {  
    4.             Object singletonObject = this.singletonObjects.get(beanName);  
    5.             if (singletonObject == null) {//第一次建立當然是空  
    6.                 beforeSingletonCreation(beanName);//這個是看看當前的beanName是否在排除列表中,如果是  
    7.                 //則丟擲異常  
    8.                 boolean recordSuppressedExceptions = (this.suppressedExceptions == null);  
    9.                 try {//這裡呼叫了上面的匿名內部類的getObject方法了,實則呼叫了createBean方法  
    10.                     singletonObject = singletonFactory.getObject();  
    11.                 }//這不,新增到了singleObjects對映表中了,以備下次使用  
    12.                 addSingleton(beanName, singletonObject);  
    13.             }  
    14.             return (singletonObject != NULL_OBJECT ? singletonObject : null);  
    15.         }  
    16.     }  

       這裡稍微清晰了,檢視singletonObjects對映表,看是否存在已經註冊的單例,如果沒有呼叫createBean方法建立一個,並且註冊到singletonObjects對映表中,否則直接返回就Ok了。

    下面就是createBean了, we are close。

    ?

    [java] view plain copy
    1. protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd,   
    2.                                                                     final Object[] args) {  
    3.         // Instantiate the bean.  
    4.         BeanWrapper instanceWrapper = null;  
    5.         if (mbd.isSingleton()) {  
    6.             instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);  
    7.         }  
    8.         if (instanceWrapper == null) {//例項化動作  
    9.             instanceWrapper = createBeanInstance(beanName, mbd, args);  
    10.         }  
    11.         //.....some codes we don't care.  
    12.         //......  
    13.         // Initialize the bean instance.  
    14.         Object exposedObject = bean;  
    15.         try {/////裝配動作  
    16.             populateBean(beanName, mbd, instanceWrapper);  
    17.             if (exposedObject != null) {//後面會講到,暫時不關心  
    18.                 exposedObject = initializeBean(beanName, exposedObject, mbd);  
    19.             }  
    20.         }  
    21.         //........some codes we don't care.  
    22.         return exposedObject;  
    23.     }  

       比較清晰(同樣去除了一些我們不關心的程式碼),上面的方法分了我們期望的兩部執行,第一例項化Bean,第二裝配Bean。

        第一步例項化主要是通過確定呼叫的構造器來最終呼叫Class.newInstance(args)方法來例項化Bean。不做細究,有興趣可以自己看看,比較簡單,主要是第二部裝配,也就是處理我們的@Autowired註解(終於找到正題了)。

    六、執行裝配

        方法populateBean執行了最終的Autowired動作,我們看一下它做了什麼?話說這塊有點麻煩了,開始之前想講幾個比較重要的類和介面吧:

        A) PropertyValue:這是一個用來表示Bean屬性的物件,其中定義了屬性的名字和值等資訊,如simpleService,和simpleDao屬性。

        B) PropertyDescriptor:這個事Bean屬性的描述符,其中定義了該屬性可能存在的setter和getter方法,以及所有Bean的Class物件。

        C) InjectionMetadata:這個是注入元資料,包含了目標Bean的Class物件,和注入元素(InjectionElement)集合.

        D) InjectionElement:這個是注入元素,包含了注入元素的Java.lang.reflect.Member 的物件,以及一個PropertyDescriptor物件。就是對java.lang.reflect.Member的一個封裝,用來執行最終的注入動作,它有兩個子類,分別是:AutowiredFieldElement表示欄位屬性,AutowiredMethodElement表示方法。

        其實最終的目標就是將PropertyValue中的value值賦給InjectionElement中的Member物件。那它是怎麼做的呢?

    [java] view plain copy
    1. protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {  
    2.         //嘗試從BeanDefinition中獲取PropertyValue的屬性集合,很明顯沒有值呢還。  
    3.         PropertyValues pvs = mbd.getPropertyValues();  
    4.         //.....其中執行了一些BeanPostProcessor的postProcessAfterInstantiation動作,我們不關心。  
    5.         //.....移除了  
    6.         //這裡比較重要,這裡會設定上面的PropertyValues的值,預設情況下是getResolvedAutowiredMode方法返回  
    7.         //0, 但是我們可以在xml配置檔案中設定<beans/>標籤的default-autowire屬性來改變它。  
    8.         if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||  
    9.                 mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {  
    10.             MutablePropertyValues newPvs = new MutablePropertyValues(pvs);  
    11.             // Add property values based on autowire by name if applicable.  
    12.             if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {  
    13.                 autowireByName(beanName, mbd, bw, newPvs);  
    14.             }  
    15.             // Add property values based on autowire by type if applicable.  
    16.             if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {  
    17.                 autowireByType(beanName, mbd, bw, newPvs);  
    18.             }  
    19.             pvs = newPvs;  
    20.         }  
    21.         boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();  
    22.         boolean needsDepCheck = (mbd.getDependencyCheck() !=   
    23.                                                 RootBeanDefinition.DEPENDENCY_CHECK_NONE);  
    24.         if (hasInstAwareBpps || needsDepCheck) {  
    25.             PropertyDescriptor[] filteredPds =   
    26.                             filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);  
    27.             if (hasInstAwareBpps) {  
    28.                 //這裡便是最最最重要的了,也就是最終的Autowired了。  
    29.                 for (BeanPostProcessor bp : getBeanPostProcessors()) {  
    30.                     if (bp instanceof InstantiationAwareBeanPostProcessor) {  
    31.                         InstantiationAwareBeanPostProcessor ibp =   
    32.                                                     (InstantiationAwareBeanPostProcessor) bp;  
    33.                         pvs = ibp.postProcessPropertyValues(//瞅到沒,這個方法哦~~~  
    34.                                         pvs, filteredPds, bw.getWrappedInstance(), beanName);  
    35.                         if (pvs == null) {  
    36.                             return;  
    37.                         }  
    38.                     }  
    39.                 }  
    40.             }  
    41.             if (needsDepCheck) {  
    42.                 checkDependencies(beanName, mbd, filteredPds, pvs);  
    43.             }  
    44.         }  
    45.         applyPropertyValues(beanName, mbd, bw, pvs);  
    46.     }  

       Spring 嘗試獲取bean definition的PropertyValue集合,開始當然是空的,然後下面便是進行根據名字或者型別為我們的PropertyValue集合進行賦值了, 在不設定<beans default-autowire="byName/byType"/>的情況下是不會呼叫這個方法的,如果設定了byName,我們來看看做了什麼?

    ?

  • protected void autowireByName(  
  •             String beanName, AbstractBeanDefinition mbd,   
  •             BeanWrapper bw, MutablePropertyValues pvs) {  
  •         //找到還沒賦值的屬性名稱,看下面方法  
  •         String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);  
  •         for (String propertyName : propertyNames) {  
  •             if (containsBean(propertyName)) {  
  •                 //遞迴呼叫getBean,如果沒有建立並註冊,有了直接返回。  
  •                 Object bean = getBean(propertyName);  
  •                 //將剛得到或建立的bean賦值給PropertyValue  
  •                 pvs.add(propertyName, bean);  
  •                 //並將該屬性名和例項註冊到依賴關係對映表dependentBeanMap和dependencyForBeanMap中  
  •                 registerDependentBean(propertyName, beanName);  
  •             }  
  •         }  
  •     }  
  • protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {  
  •         Set<String> result = new TreeSet<String>();  
  •         PropertyValues pvs = mbd.getPropertyValues();  
  •         PropertyDescriptor[] pds = bw.getPropertyDescriptors();  
  •         //遍歷bean的所有屬性,並將符合條件的屬性名新增到結果列表中  
  •         for (PropertyDescriptor pd : pds) {  
  •             if (pd.getWriteMethod() != null   
  •                 && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&  
  •                     !BeanUtils.isSimpleProperty(pd.getPropertyType())) {  
  •                 result.add(pd.getName());  
  •             }  
  •         }  
  •         return StringUtils.toStringArray(result);  
  •     }  
  •    上面兩段程式碼的意思是,檢視當前bean的所有屬性(描述符),然後依次判斷查詢符合條件的屬性,並新增到屬性名稱陣列中,然後遍歷這個陣列,對其中的屬性名依次呼叫getBean(propertyName)方法來獲取或建立該名稱的bean例項,並將該bean例項設為PropertyValue的value值,最後新增到依賴關係對映表中(dependencyForBeanMap和dependentBeanMap)。好了此時PropertyValues有值了,後面就可以用它來注入到bean的屬性中了。我們接著看上面populateBean方法。

        PropertyValue值設定後,Spring會呼叫getBeanPostProcessor方法遍歷Bean工廠中註冊的所有BeanPostProcessor,其中就包括AutowiredAnnotationBeanPostProcessor(這些BeanPostProcessor都是系統預設硬編碼註冊到bean工廠中的)。接著就會呼叫AutowiredAnnotationBeanPostProcessor的postProcessPropertyValues方法,並將之前的PropertyValues和bean例項傳遞進去。

    ?

  • //雖然PropertyValues屬性傳遞過去了,但是並沒有使用它直接賦值給屬性變數(還不清楚為什麼會傳遞它,其實沒用到)  
  • @Override  
  • public PropertyValues postProcessPropertyValues(PropertyValues pvs,   
  •                 PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {  
  •         //呼叫下面的方法獲取InjectionMetadata物件(其實InjectionElement集合)  
  •         InjectionMetadata metadata = findAutowiringMetadata(bean.getClass());  
  •         try {  
  •             metadata.inject(bean, beanName, pvs);  
  •         }  
  •         return pvs;  
  •     }  
  • private InjectionMetadata findAutowiringMetadata(Class<?> clazz) {  
  •         // 先找快取  
  •         InjectionMetadata metadata = this.injectionMetadataCache.get(clazz);  
  •         if (metadata == null) {  
  •             synchronized (this.injectionMetadataCache) {  
  •                 metadata = this.injectionMetadataCache.get(clazz);  
  •                 if (metadata == null) {  
  •                     //快取沒有,呼叫buildAutowiringMetadata方法構建  
  •                     metadata = buildAutowiringMetadata(clazz);  
  •                     this.injectionMetadataCache.put(clazz, metadata);  
  •                 }  
  •             }  
  •         }  
  •         return metadata;  
  •     }  
  • private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {  
  •         LinkedList<InjectionMetadata.InjectedElement> elements =   
  •                                         new LinkedList<InjectionMetadata.InjectedElement>();  
  •         Class<?> targetClass = clazz;  
  •         do {//這裡一個迴圈,因為要考慮父類的欄位和方法  
  •             LinkedList<InjectionMetadata.InjectedElement> currElements =   
  •                                     new LinkedList<InjectionMetadata.InjectedElement>();  
  •             for (Field field : targetClass.getDeclaredFields()) {  
  •                 //遍歷每一個field,找到被標記為@Autowired的field  
  •                 Annotation annotation = findAutowiredAnnotation(field);  
  •                 if (annotation != null) {  
  •                     if (Modifier.isStatic(field.getModifiers())) {  
  •                         continue;//不可一世static的。  
  •                     }  
  •                     boolean required = determineRequiredStatus(annotation);  
  •                     //建立AutowiredFieldElement。  
  •                     currElements.add(new AutowiredFieldElement(field, required));  
  •                 }  
  •             }  
  •             for (Method method : targetClass.getDeclaredMethods()) {  
  •                 //遍歷所有方法,這裡有個橋方法的處理,我們不關心  
  •                 Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);  
  •                 Annotation annotation = BridgeMethodResolver  
  •                                     .isVisibilityBridgeMethodPair(method, bridgedMethod) ?  
  •                                         findAutowiredAnnotation(bridgedMethod) :  
  •                                      findAutowiredAnnotation(method);  
  •                 if (annotation != null &&   
  •                             method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {  
  •                     if (Modifier.isStatic(method.getModifiers())) {  
  •                         continue;  
  •                     }  
  •                     if (method.getParameterTypes().length == 0) {  
  •                     }  
  •                     boolean required = determineRequiredStatus(annotation);  
  •                     PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);  
  •                     //建立AutowiredMethodElement。  
  •                     currElements.add(new AutowiredMethodElement(method, required, pd));  
  •                 }  
  •             }  
  •             elements.addAll(0, currElements);  
  •             targetClass = targetClass.getSuperclass();  
  •         }  
  •         while (targetClass != null && targetClass != Object.class);  
  •         //將InjectionElement集合新增到新建的InjectionMetadata中。  
  •         return new InjectionMetadata(clazz, elements);  
  •     }  
  •    上面三個方法看似複雜其實很簡單,首先Spring嘗試呼叫findAutowiringMetadata方法獲取該bean的InjectionMetadata例項(也就是有哪些屬性需要被自動裝配,也就是查詢被@Autowired註解標記的元素)。怎麼獲取呢?首先去快取裡面找,找不到就遍歷bean的和父類的欄位域和方法,如果別標記為@Autowired並且不是靜態的就新增到InjectionMetadata中,並新增到快取中(各種快取啊)。獲得InjectionMetadata物件後便遍歷其中的所有InjectionElement物件,呼叫其中的inject方法。前面說了InjectionElement有兩個實現類,我們只看一個就可以,因為基本相同:

    ?

  • @Override  
  •         protected void inject(Object bean, String beanName, PropertyValues pvs)   
  •                                                             throws Throwable {  
  •             Field field = (Field) this.member;  
  •             try {  
  •                 Object value;  
  •                 if (this.cached) {  
  •                     value = resolvedCachedArgument(beanName, this.cachedFieldValue);  
  •                 }  
  •                 else {  
  •                     DependencyDescriptor descriptor   
  •                                         = new DependencyDescriptor(field, this.required);  
  •                     Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);  
  •                     TypeConverter typeConverter = beanFactory.getTypeConverter();  
  •                     //這裡是重中之重,獲取真正的屬性值。  
  •                     value = beanFactory.resolveDependency(descriptor, beanName,   
  •                                                 autowiredBeanNames, typeConverter);  
  •                 }  
  •                 if (value != null) {  
  •                     ReflectionUtils.makeAccessible(field);  
  •                     field.set(bean, value);//最終賦值結束。  
  •                 }  
  •             }  
  •         }  
  •     }  
  •   可以看到,雖然PropertyValues屬性傳遞過去了,但是並沒有使用它直接賦值給屬性變數(還不清楚為什麼會傳遞它,其實沒用到),而是通過呼叫bean工廠的resolveDependency方法來獲取屬性值得。那我們看一下resolveDependency做了什麼?

    ?

  • protected Object doResolveDependency(DependencyDescriptor descriptor,   
  •                                         Class<?> type, String beanName,  
  •                                      Set<String> autowiredBeanNames,   
  •                                 TypeConverter typeConverter) throws BeansException  {  
  •         if (type.isArray()) {//如果屬性型別是陣列  
  •             Class<?> componentType = type.getComponentType();  
  •             Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType, descriptor);  
  •             if (autowiredBeanNames != null) {  
  •                 autowiredBeanNames.addAll(matchingBeans.keySet());  
  •             }  
  •             TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());  
  •             return converter.convertIfNecessary(matchingBeans.values(), type);  
  •         }//如果屬性是集合,並且是介面  
  •         else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {  
  •             Class<?> elementType = descriptor.getCollectionType();  
  •             Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType, descriptor);  
  •             if (autowiredBeanNames != null) {  
  •                 autowiredBeanNames.addAll(matchingBeans.keySet());  
  •             }  
  •             TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());  
  •             return converter.convertIfNecessary(matchingBeans.values(), type);  
  •         }//如果屬性是Map並且是介面  
  •         else if (Map.class.isAssignableFrom(type) && type.isInterface()) {  
  •             Class<?> keyType = descriptor.getMapKeyType();  
  •             Class<?> valueType = descriptor.getMapValueType();  
  •             Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, descriptor);  
  •             if (autowiredBeanNames != null) {  
  •                 autowiredBeanNames.addAll(matchingBeans.keySet());  
  •             }  
  •             return matchingBeans;  
  •         }//自定義型別了  
  •         else {//都呼叫了這個方法  
  •             Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);  
  •             if (matchingBeans.size() > 1) {  
  •                 String primaryBeanName = determinePrimaryCandidate(matchingBeans, descriptor);  
  •                 if (autowiredBeanNames != null) {  
  •                     autowiredBeanNames.add(primaryBeanName);  
  •                 }  
  •                 return matchingBeans.get(primaryBeanName);  
  •             }  
  •             // We have exactly one match.  
  •             Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();  
  •             if (autowiredBeanNames != null) {  
  •                 autowiredBeanNames.add(entry.getKey());  
  •             }  
  •             return entry.getValue();  
  •         }  
  •     }  
  •    這個方法其實就是根據型別到bean工廠中查詢型別匹配的bean例項,然後就看到了這幾個條件分支語句,如果是陣列,集合,對映表,自定義型別都執行了差不多的操作,findAutowireCandidate方法。這個方法會去工廠中執行型別匹配的查詢,將匹配的結果集返回,不同的是,集合陣列型別會通過TypeConverter進行結果的轉換。

        到此為止,找到了屬性的匹配值,然後反射賦值就完成了整個的自動裝配過程。可以看出,@Autowired是通過型別來進行自動裝配的。

        上面是屬性的賦值過程也就是InjectionFieldElement的inject方法,InjectionMethodElement的inject方法大致相同只是對每一個方法引數執行一次resolveDependency方法來獲取引數值,然後反射執行方法。

        到此為止,整個例項化和裝配過程也就講完了,我們總結一下:

    1)一切都是從bean工廠的getBean方法開始的,一旦該方法呼叫總會返回一個bean例項,無論當前是否存在,不存在就例項化一個並裝配,否則直接返回。

    2)例項化和裝配過程中會多次遞迴呼叫getBean方法來解決類之間的依賴。

    3)Spring幾乎考慮了所有可能性,所以方法特別複雜但完整有條理。

    4)@Autowired最終是根據型別來查詢和裝配元素的,但是我們設定了<beans default-autowire="byName"/>後會影響最終的型別匹配查詢。因為在前面有根據BeanDefinition的autowire型別設定PropertyValue值得一步,其中會有新例項的建立和註冊。就是那個autowireByName方法。

    七、一切的開始

        我們上面講完了整個Autowire過程了。那麼,還有一個問題,上一篇我們知道了什麼時候執行的配置檔案讀取和元件掃描,但Spring MVC是在什麼時候開始執行真個例項化過程的呢?很簡單就在元件掃描完成之後,bean工廠的refresh方法中(還記得嗎?)

    ?

    [java] view plain copy
    1. public void refresh() throws BeansException, IllegalStateException {  
    2.         synchronized (this.startupShutdownMonitor) {  
    3.             prepareRefresh();  
    4.             //前面說過,這裡面執行了,元件掃描和配置檔案讀取  
    5.             ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  
    6.             prepareBeanFactory(beanFactory);  
    7.             try {  
    8.                 postProcessBeanFactory(beanFactory);  
    9.                 invokeBeanFactoryPostProcessors(beanFactory);  
    10.                 //這裡註冊了BeanPostProcessor,包括AutowiredAnnotationBeanPostProcessor  
    11.                 registerBeanPostProcessors(beanFactory);  
    12.                 initMessageSource();  
    13.                 initApplicationEventMulticaster();  
    14.                 onRefresh();  
    15.                 registerListeners();  
    16.                 //這裡就執行了所有非延遲載入的例項化工作。//here  
    17.                 finishBeanFactoryInitialization(beanFactory);  
    18.                 finishRefresh();  
    19.             }  
    20.         }  
    21.     }  

     就是上面的finishBeanFactoryInitialization方法執行了裝配工作,該方法會呼叫bean工廠的preInstantiateSingletons方法,這個方法會遍歷所有註冊的bean definition例項,如果是單例並且是非延遲載入的就呼叫getBean方法。

        好了,到此為止我們就清晰的瞭解了,Spring MVC的例項化和自動裝配工作了,如有問題歡迎評論中提出,我們一起討論。