Spring MVC 解讀——@Autowired、@Controller、@Service從原理層面來分析

Spring MVC 解讀——@Autowired

一、@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實現類完成。那我們不妨看一下他們的定義:

 
public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

   BeanPostProcessor就一個回調接口,定義了兩個方法聲明,一個是實例化前被調用,一個是實例化後被調用,沒啥好看的,我們直接看看它的實現類AutowiredAnnotationBeanPostProcessor:


 

BeanPostProcessor implementation that autowires annotated fields, setter methods and arbitrary 
config methods. Such members to be injected are detected through a Java 5 annotation: 
by default, Spring's @Autowired and @Value annotations.Also supports JSR-330's @Inject 
annotation, if available, as a direct alternative to Spring's own @Autowired.
 
Note: A default AutowiredAnnotationBeanPostProcessor will be registered by 
the "context:annotation-config" and "context:component-scan" XML tags.
 
NOTE: Annotation injection will be performed before XML 
injection; thus the latter configuration will override the former for properties 
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工廠中的屬性和方法:

 
//==========================================================================================
//==============================DefaultListableBeanFactory================================
//==========================================================================================
//beanName-beanDefinition 的映射表
private final Map<String, BeanDefinition> beanDefinitionMap = 
                                            new ConcurrentHashMap<String, BeanDefinition>(64);
//beanName 列表
private final List<String> beanDefinitionNames = new ArrayList<String>();
//==========================================================================================
//=============================AbstractBeanFactory=================================
//==========================================================================================
//註冊了所有的BeanPostProcessor實例,包括前面提到的用來處理@Autowired註解的
//AutowiredAnnotationBeanPostProcessor 
private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();
//可能存在的父親Bean工廠
private BeanFactory parentBeanFactory;
//==========================================================================================
//==============================DefaultSingletonBeanRegistry================================
//==========================================================================================
//beanName--bean單例的映射表
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);
//註冊過的beanName集合
private final Set<String> registeredSingletons = new LinkedHashSet<String>(64);
//beanName與該bean所依賴的Beans集合的映射表,如simpleDao依賴與simpleService,如果還有其他
service使用該Dao,如simpleService2那麼是simpleDao->[simpleService,simpleService2]
private final Map<String, Set<String>> dependentBeanMap 
                                            = new ConcurrentHashMap<String, Set<String>>(64);
//恰好與上面相反,beanName與該bean所包含的beans的集合映射表,如simpleController->[simpleService]
private final Map<String, Set<String>> dependenciesForBeanMap 
                                            = 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
public Object getSingleton(String beanName, ObjectFactory singletonFactory) {
        //這不就是上面說的bean實例映射表嗎?哈,被同步了,保證線程安全啊
        synchronized (this.singletonObjects) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {//第一次創建當然是空
                beforeSingletonCreation(beanName);//這個是看看當前的beanName是否在排除列表中,如果是
                //則拋出異常
                boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
                try {//這裏調用了上面的匿名內部類的getObject方法了,實則調用了createBean方法
                    singletonObject = singletonFactory.getObject();
                }//這不,添加到了singleObjects映射表中了,以備下次使用
                addSingleton(beanName, singletonObject);
            }
            return (singletonObject != NULL_OBJECT ? singletonObject : null);
        }
    }

   這裏稍微清晰了,查看singletonObjects映射表,看是否存在已經註冊的單例,如果沒有調用createBean方法創建一個,並且註冊到singletonObjects映射表中,否則直接返回就Ok了。

下面就是createBean了, we are close。

 
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, 
                                                                    final Object[] args) {
        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {//實例化動作
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        //.....some codes we don't care.
        //......
        // Initialize the bean instance.
        Object exposedObject = bean;
        try {/////裝配動作
            populateBean(beanName, mbd, instanceWrapper);
            if (exposedObject != null) {//後面會講到,暫時不關心
                exposedObject = initializeBean(beanName, exposedObject, mbd);
            }
        }
        //........some codes we don't care.
        return exposedObject;
    }

   比較清晰(同樣去除了一些我們不關心的代碼),上面的方法分了我們期望的兩部執行,第一實例化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對象。那它是怎麼做的呢?


 
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
        //嘗試從BeanDefinition中獲取PropertyValue的屬性集合,很明顯沒有值呢還。
        PropertyValues pvs = mbd.getPropertyValues();
        //.....其中執行了一些BeanPostProcessor的postProcessAfterInstantiation動作,我們不關心。
        //.....移除了
 
        //這裏比較重要,這裏會設置上面的PropertyValues的值,默認情況下是getResolvedAutowiredMode方法返回
        //0, 但是我們可以在xml配置文件中設置<beans/>標籤的default-autowire屬性來改變它。
        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
            // Add property values based on autowire by name if applicable.
            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
                autowireByName(beanName, mbd, bw, newPvs);
            }
            // Add property values based on autowire by type if applicable.
            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
                autowireByType(beanName, mbd, bw, newPvs);
            }
            pvs = newPvs;
        }
        boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
        boolean needsDepCheck = (mbd.getDependencyCheck() != 
                                                RootBeanDefinition.DEPENDENCY_CHECK_NONE);
        if (hasInstAwareBpps || needsDepCheck) {
            PropertyDescriptor[] filteredPds = 
                            filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            if (hasInstAwareBpps) {
                //這裏便是最最最重要的了,也就是最終的Autowired了。
                for (BeanPostProcessor bp : getBeanPostProcessors()) {
                    if (bp instanceof InstantiationAwareBeanPostProcessor) {
                        InstantiationAwareBeanPostProcessor ibp = 
                                                    (InstantiationAwareBeanPostProcessor) bp;
                        pvs = ibp.postProcessPropertyValues(//瞅到沒,這個方法哦~~~
                                        pvs, filteredPds, bw.getWrappedInstance(), beanName);
                        if (pvs == null) {
                            return;
                        }
                    }
                }
            }
            if (needsDepCheck) {
                checkDependencies(beanName, mbd, filteredPds, pvs);
            }
        }
        applyPropertyValues(beanName, mbd, bw, pvs);
    }

   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方法中(還記得嗎?)

 
public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            prepareRefresh();
            //前面說過,這裏面執行了,組件掃描和配置文件讀取
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
            prepareBeanFactory(beanFactory);
            try {
                postProcessBeanFactory(beanFactory);
                invokeBeanFactoryPostProcessors(beanFactory);
                //這裏註冊了BeanPostProcessor,包括AutowiredAnnotationBeanPostProcessor
                registerBeanPostProcessors(beanFactory);
                initMessageSource();
                initApplicationEventMulticaster();
                onRefresh();
                registerListeners();
                //這裏就執行了所有非延遲加載的實例化工作。//here
                finishBeanFactoryInitialization(beanFactory);
                finishRefresh();
            }
        }
    }

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

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


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

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