springMVC常用註解解讀

Spring MVC 解讀——@Autowired

一、@Autowired

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

[java] view plain copy
  1. @Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD,  
  2.                          ElementType.ANNOTATION_TYPE})  
  3. @Retention(RetentionPolicy.RUNTIME)  
  4. @Documented  
  5. public @interface Autowired {  
  6.     boolean required() default true;  
  7. }  
 

 很明顯這個註解可以用到構造器,變量域,方法,註解類型上。文檔上這樣描述:將一個構造器,變量域,setter方法,config方法標記爲被Spring DI 工具自動裝配。換句話說,我們視圖從bean 工廠中獲取一個bean時,Spring會自動爲我們裝配該bean中標記爲@Autowired的元素,而無需我們手動完成。這些相信大家都明白,但問題是,Spring是怎樣做到的?在Spring MVC中怎樣做到的?什麼時候進行的自動裝配?下面我們就來探究下這些問題。

二、BeanPostProcessor

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

[java] view plain copy
  1. <pre name="code" class="java">Note that actual injection is performed through a BeanPostProcessor   
  2. which in turn means that you cannot use @Autowired to inject references into BeanPostProcessor  
  3. or BeanFactoryPostProcessor types.   
  4. Please consult the javadoc for the AutowiredAnnotationBeanPostProcessor class   
  5. (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'@Inject   
  4. annotation, if available, as a direct alternative to Spring's own @Autowired.  
  5.    
  6. Note: A default AutowiredAnnotationBeanPostProcessor will be registered by   
  7. the "context:annotation-config" and "context:component-scan" XML tags.  
  8.    
  9. NOTE: Annotation injection will be performed before XML   
  10. injection; thus the latter configuration will override the former for properties   
  11. 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實例執行了自動裝配,那麼它做了什麼呢?

三、磨刀砍柴    

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


[java] view plain copy
  1. //==================================Controller  
  2. @Controller  
  3. public class SimpleController {  
  4.     @Autowired  
  5.     private SimpleService simpleService;  
  6. }  
  7. //==================================Service  
  8. @Service("simpleService")  
  9. public class SimpleServiceImpl implements SimpleService {  
  10.     @Autowired  
  11.     private SimpleDao simpleDao;  
  12. }  
  13. //===================================Repository  
  14. @Repository("simpleDao")  
  15. public class SimpleDaoImpl implements SimpleDao {  
  16. }  

 

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實例的映射表,還有依賴關係圖。理解了這個對下面的實例化以及裝配過程會有很大幫助。

五,實例化與裝配

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


[java] view plain copy
  1. public Object getBean(String name) throws BeansException {  
  2.     return doGetBean(name, nullnullfalse);  
  3. }  
  4.    
  5. @SuppressWarnings("unchecked")  
  6. protected <T> T doGetBean(final String name, final Class<T> requiredType,   
  7.                           final Object[] args, boolean typeCheckOnly)throws BeansException {  
  8.         //去掉工廠bean的前綴或者將別名轉化爲規範名  
  9.         final String beanName = transformedBeanName(name);  
  10.         Object bean;  
  11.         // 檢查是否有已經註冊的bean實例  
  12.         Object sharedInstance = getSingleton(beanName);  
  13.         if (sharedInstance != null && args == null) {  
  14.             //如果是工廠bean,獲取工廠bean創建的bean  
  15.             bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);  
  16.         }  
  17.         else {  
  18.             //判斷是否有父工廠,並且其中是否存在該bean實例?  
  19.             BeanFactory parentBeanFactory = getParentBeanFactory();  
  20.             if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {  
  21.                 String nameToLookup = originalBeanName(name);  
  22.                 if (args != null) {  
  23.                     return (T) parentBeanFactory.getBean(nameToLookup, args);  
  24.                 }  
  25.                 else {  
  26.                     return parentBeanFactory.getBean(nameToLookup, requiredType);  
  27.                 }  
  28.             }  
  29.             if (!typeCheckOnly) {  
  30.                 markBeanAsCreated(beanName);//將該beanName標記爲已經實例化  
  31.             }  
  32.             //獲取該beanName對應的BeanDefinition實例,從上面說到的beanDefinitionMap表中查找  
  33.             final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);  
  34.             checkMergedBeanDefinition(mbd, beanName, args);  
  35.             //判斷是否有依賴bean  
  36.             String[] dependsOn = mbd.getDependsOn();  
  37.             if (dependsOn != null) {  
  38.                 for (String dependsOnBean : dependsOn) {  
  39.                     getBean(dependsOnBean);//如果有依賴bean,遞歸調用getBean方法  
  40.                     registerDependentBean(dependsOnBean, beanName);//將依賴關係保存到 上面提到的  
  41.                     //dependBeanMap和dependencyForBeanMap中。  
  42.                 }  
  43.             }  
  44.             // 真正的開始牀架bean實例了。激動吧  
  45.             if (mbd.isSingleton()) {//beanDefinition中指定該實例爲單例  
  46.                 //去工廠中獲取單例,如果沒有創建一個,然後添加到工廠中,否則直接返回  
  47.                 sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {  
  48.                     public Object getObject() throws BeansException {  
  49.                         try {  
  50.                             return createBean(beanName, mbd, args);  
  51.                         }  
  52.                     }  
  53.                 });  
  54.                 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);  
  55.             }  
  56.             else if (mbd.isPrototype()) {//原型方式,每次都創建一個新的實例  
  57.                 Object prototypeInstance = null;  
  58.                 try {  
  59.                     beforePrototypeCreation(beanName);  
  60.                     prototypeInstance = createBean(beanName, mbd, args);  
  61.                 }  
  62.                 finally {  
  63.                     afterPrototypeCreation(beanName);  
  64.                 }  
  65.                 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);  
  66.             }  
  67.             else {//其他方式,如目前主體無關,不贅述  
  68.             }  
  69.         }  
  70.         return (T) bean;  
  71.     }  

 

   這個方法好長,真的好長,我還刪除了一些與當前主體無關的代碼呢,好吧,不要被嚇住,如果是自己寫的代碼,再長都很容易弄懂,類的繼承關係再複雜都能輕車熟路,那是因爲我們都清楚的知道每一行的用意,看別人的代碼一樣,多看幾遍就明白了,再複雜都一樣。

    首先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.    
  7.         //這裏比較重要,這裏會設置上面的PropertyValues的值,默認情況下是getResolvedAutowiredMode方法返回  
  8.         //0, 但是我們可以在xml配置文件中設置<beans/>標籤的default-autowire屬性來改變它。  
  9.         if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||  
  10.                 mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {  
  11.             MutablePropertyValues newPvs = new MutablePropertyValues(pvs);  
  12.             // Add property values based on autowire by name if applicable.  
  13.             if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {  
  14.                 autowireByName(beanName, mbd, bw, newPvs);  
  15.             }  
  16.             // Add property values based on autowire by type if applicable.  
  17.             if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {  
  18.                 autowireByType(beanName, mbd, bw, newPvs);  
  19.             }  
  20.             pvs = newPvs;  
  21.         }  
  22.         boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();  
  23.         boolean needsDepCheck = (mbd.getDependencyCheck() !=   
  24.                                                 RootBeanDefinition.DEPENDENCY_CHECK_NONE);  
  25.         if (hasInstAwareBpps || needsDepCheck) {  
  26.             PropertyDescriptor[] filteredPds =   
  27.                             filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);  
  28.             if (hasInstAwareBpps) {  
  29.                 //這裏便是最最最重要的了,也就是最終的Autowired了。  
  30.                 for (BeanPostProcessor bp : getBeanPostProcessors()) {  
  31.                     if (bp instanceof InstantiationAwareBeanPostProcessor) {  
  32.                         InstantiationAwareBeanPostProcessor ibp =   
  33.                                                     (InstantiationAwareBeanPostProcessor) bp;  
  34.                         pvs = ibp.postProcessPropertyValues(//瞅到沒,這個方法哦~~~  
  35.                                         pvs, filteredPds, bw.getWrappedInstance(), beanName);  
  36.                         if (pvs == null) {  
  37.                             return;  
  38.                         }  
  39.                     }  
  40.                 }  
  41.             }  
  42.             if (needsDepCheck) {  
  43.                 checkDependencies(beanName, mbd, filteredPds, pvs);  
  44.             }  
  45.         }  
  46.         applyPropertyValues(beanName, mbd, bw, pvs);  
  47.     }  

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

[java] view plain copy
  1. protected void autowireByName(  
  2.             String beanName, AbstractBeanDefinition mbd,   
  3.             BeanWrapper bw, MutablePropertyValues pvs) {  
  4.         //找到還沒賦值的屬性名稱,看下面方法  
  5.         String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);  
  6.         for (String propertyName : propertyNames) {  
  7.             if (containsBean(propertyName)) {  
  8.                 //遞歸調用getBean,如果沒有創建並註冊,有了直接返回。  
  9.                 Object bean = getBean(propertyName);  
  10.                 //將剛得到或創建的bean賦值給PropertyValue  
  11.                 pvs.add(propertyName, bean);  
  12.                 //並將該屬性名和實例註冊到依賴關係映射表dependentBeanMap和dependencyForBeanMap中  
  13.                 registerDependentBean(propertyName, beanName);  
  14.             }  
  15.         }  
  16.     }  
  17.    
  18. protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {  
  19.         Set<String> result = new TreeSet<String>();  
  20.         PropertyValues pvs = mbd.getPropertyValues();  
  21.         PropertyDescriptor[] pds = bw.getPropertyDescriptors();  
  22.         //遍歷bean的所有屬性,並將符合條件的屬性名添加到結果列表中  
  23.         for (PropertyDescriptor pd : pds) {  
  24.             if (pd.getWriteMethod() != null   
  25.                 && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&  
  26.                     !BeanUtils.isSimpleProperty(pd.getPropertyType())) {  
  27.                 result.add(pd.getName());  
  28.             }  
  29.         }  
  30.         return StringUtils.toStringArray(result);  
  31.     }  

 

   上面兩段代碼的意思是,查看當前bean的所有屬性(描述符),然後依次判斷查找符合條件的屬性,並添加到屬性名稱數組中,然後遍歷這個數組,對其中的屬性名依次調用getBean(propertyName)方法來獲取或創建該名稱的bean實例,並將該bean實例設爲PropertyValue的value值,最後添加到依賴關係映射表中(dependencyForBeanMap和dependentBeanMap)。好了此時PropertyValues有值了,後面就可以用它來注入到bean的屬性中了。我們接着看上面populateBean方法。

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

[java] view plain copy
  1. //雖然PropertyValues屬性傳遞過去了,但是並沒有使用它直接賦值給屬性變量(還不清楚爲什麼會傳遞它,其實沒用到)  
  2. @Override  
  3. public PropertyValues postProcessPropertyValues(PropertyValues pvs,   
  4.                 PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {  
  5.         //調用下面的方法獲取InjectionMetadata對象(其實InjectionElement集合)  
  6.         InjectionMetadata metadata = findAutowiringMetadata(bean.getClass());  
  7.         try {  
  8.             metadata.inject(bean, beanName, pvs);  
  9.         }  
  10.         return pvs;  
  11.     }  
  12.    
  13. private InjectionMetadata findAutowiringMetadata(Class<?> clazz) {  
  14.         // 先找緩存  
  15.         InjectionMetadata metadata = this.injectionMetadataCache.get(clazz);  
  16.         if (metadata == null) {  
  17.             synchronized (this.injectionMetadataCache) {  
  18.                 metadata = this.injectionMetadataCache.get(clazz);  
  19.                 if (metadata == null) {  
  20.                     //緩存沒有,調用buildAutowiringMetadata方法構建  
  21.                     metadata = buildAutowiringMetadata(clazz);  
  22.                     this.injectionMetadataCache.put(clazz, metadata);  
  23.                 }  
  24.             }  
  25.         }  
  26.         return metadata;  
  27.     }  
  28.    
  29. private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {  
  30.         LinkedList<InjectionMetadata.InjectedElement> elements =   
  31.                                         new LinkedList<InjectionMetadata.InjectedElement>();  
  32.         Class<?> targetClass = clazz;  
  33.         do {//這裏一個循環,因爲要考慮父類的字段和方法  
  34.             LinkedList<InjectionMetadata.InjectedElement> currElements =   
  35.                                     new LinkedList<InjectionMetadata.InjectedElement>();  
  36.             for (Field field : targetClass.getDeclaredFields()) {  
  37.                 //遍歷每一個field,找到被標記爲@Autowired的field  
  38.                 Annotation annotation = findAutowiredAnnotation(field);  
  39.                 if (annotation != null) {  
  40.                     if (Modifier.isStatic(field.getModifiers())) {  
  41.                         continue;//不可一世static的。  
  42.                     }  
  43.                     boolean required = determineRequiredStatus(annotation);  
  44.                     //創建AutowiredFieldElement。  
  45.                     currElements.add(new AutowiredFieldElement(field, required));  
  46.                 }  
  47.             }  
  48.             for (Method method : targetClass.getDeclaredMethods()) {  
  49.                 //遍歷所有方法,這裏有個橋方法的處理,我們不關心  
  50.                 Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);  
  51.                 Annotation annotation = BridgeMethodResolver  
  52.                                     .isVisibilityBridgeMethodPair(method, bridgedMethod) ?  
  53.                                         findAutowiredAnnotation(bridgedMethod) :  
  54.                                      findAutowiredAnnotation(method);  
  55.                 if (annotation != null &&   
  56.                             method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {  
  57.                     if (Modifier.isStatic(method.getModifiers())) {  
  58.                         continue;  
  59.                     }  
  60.                     if (method.getParameterTypes().length == 0) {  
  61.                     }  
  62.                     boolean required = determineRequiredStatus(annotation);  
  63.                     PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);  
  64.                     //創建AutowiredMethodElement。  
  65.                     currElements.add(new AutowiredMethodElement(method, required, pd));  
  66.                 }  
  67.             }  
  68.             elements.addAll(0, currElements);  
  69.             targetClass = targetClass.getSuperclass();  
  70.         }  
  71.         while (targetClass != null && targetClass != Object.class);  
  72.         //將InjectionElement集合添加到新建的InjectionMetadata中。  
  73.         return new InjectionMetadata(clazz, elements);  
  74.     }  

 

   上面三個方法看似複雜其實很簡單,首先Spring嘗試調用findAutowiringMetadata方法獲取該bean的InjectionMetadata實例(也就是有哪些屬性需要被自動裝配,也就是查找被@Autowired註解標記的元素)。怎麼獲取呢?首先去緩存裏面找,找不到就遍歷bean的和父類的字段域和方法,如果別標記爲@Autowired並且不是靜態的就添加到InjectionMetadata中,並添加到緩存中(各種緩存啊)。獲得InjectionMetadata對象後便遍歷其中的所有InjectionElement對象,調用其中的inject方法。前面說了InjectionElement有兩個實現類,我們只看一個就可以,因爲基本相同:

[java] view plain copy
  1. @Override  
  2.         protected void inject(Object bean, String beanName, PropertyValues pvs)   
  3.                                                             throws Throwable {  
  4.             Field field = (Field) this.member;  
  5.             try {  
  6.                 Object value;  
  7.                 if (this.cached) {  
  8.                     value = resolvedCachedArgument(beanName, this.cachedFieldValue);  
  9.                 }  
  10.                 else {  
  11.                     DependencyDescriptor descriptor   
  12.                                         = new DependencyDescriptor(field, this.required);  
  13.                     Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);  
  14.                     TypeConverter typeConverter = beanFactory.getTypeConverter();  
  15.                     //這裏是重中之重,獲取真正的屬性值。  
  16.                     value = beanFactory.resolveDependency(descriptor, beanName,   
  17.                                                 autowiredBeanNames, typeConverter);  
  18.                 }  
  19.                 if (value != null) {  
  20.                     ReflectionUtils.makeAccessible(field);  
  21.                     field.set(bean, value);//最終賦值結束。  
  22.                 }  
  23.             }  
  24.         }  
  25.     }  

 

  可以看到,雖然PropertyValues屬性傳遞過去了,但是並沒有使用它直接賦值給屬性變量(還不清楚爲什麼會傳遞它,其實沒用到),而是通過調用bean工廠的resolveDependency方法來獲取屬性值得。那我們看一下resolveDependency做了什麼?

[java] view plain copy
  1. protected Object doResolveDependency(DependencyDescriptor descriptor,   
  2.                                         Class<?> type, String beanName,  
  3.                                      Set<String> autowiredBeanNames,   
  4.                                 TypeConverter typeConverter) throws BeansException  {  
  5.         if (type.isArray()) {//如果屬性類型是數組  
  6.             Class<?> componentType = type.getComponentType();  
  7.             Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType, descriptor);  
  8.             if (autowiredBeanNames != null) {  
  9.                 autowiredBeanNames.addAll(matchingBeans.keySet());  
  10.             }  
  11.             TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());  
  12.             return converter.convertIfNecessary(matchingBeans.values(), type);  
  13.         }//如果屬性是集合,並且是接口  
  14.         else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {  
  15.             Class<?> elementType = descriptor.getCollectionType();  
  16.             Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType, descriptor);  
  17.             if (autowiredBeanNames != null) {  
  18.                 autowiredBeanNames.addAll(matchingBeans.keySet());  
  19.             }  
  20.             TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());  
  21.             return converter.convertIfNecessary(matchingBeans.values(), type);  
  22.         }//如果屬性是Map並且是接口  
  23.         else if (Map.class.isAssignableFrom(type) && type.isInterface()) {  
  24.             Class<?> keyType = descriptor.getMapKeyType();  
  25.             Class<?> valueType = descriptor.getMapValueType();  
  26.             Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, descriptor);  
  27.             if (autowiredBeanNames != null) {  
  28.                 autowiredBeanNames.addAll(matchingBeans.keySet());  
  29.             }  
  30.             return matchingBeans;  
  31.         }//自定義類型了  
  32.         else {//都調用了這個方法  
  33.             Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);  
  34.             if (matchingBeans.size() > 1) {  
  35.                 String primaryBeanName = determinePrimaryCandidate(matchingBeans, descriptor);  
  36.                 if (autowiredBeanNames != null) {  
  37.                     autowiredBeanNames.add(primaryBeanName);  
  38.                 }  
  39.                 return matchingBeans.get(primaryBeanName);  
  40.             }  
  41.             // We have exactly one match.  
  42.             Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();  
  43.             if (autowiredBeanNames != null) {  
  44.                 autowiredBeanNames.add(entry.getKey());  
  45.             }  
  46.             return entry.getValue();  
  47.         }  
  48.     }  

 

   這個方法其實就是根據類型到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的實例化和自動裝配工作了,如有問題歡迎評論中提出,我們一起討論。


轉:http://my.oschina.net/HeliosFly/blog/203902

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章