spring源碼系列-從@Autowired與@Resource異同中看依賴注入

上一篇文章spring源碼系列-Bean的創(chuàng)建流程中,我們抽絲剝繭的去分析bean的創(chuàng)建流程,終于揭開了spring創(chuàng)建bean的“黑幕”,我們對spring中bean的創(chuàng)建流程有了大概的了解。但是我們很少會直接用BeanFactory.getBean的方式去獲取進而使用Bean,常規(guī)操作一般是基于注解注入,如@Autowired,@Resource等。那么這些注解是如何做依賴注入的?幕后又有哪些操作,是“人性的扭曲,還是道德的淪喪”,下面我們一起走進依賴注入(IOC/DI)的世界。本文可以分為以下幾個板塊

  1. 前言
  2. spring的依賴注入
    2.1 什么是依賴注入
    2.2 依賴注入的常見方式
    2.3 整體bean的創(chuàng)建流程
    2.4 三種注入方式
    2.4.1 set注入
    2.4.1.1 set注入的使用方法
    2.4.1.2 set注入源碼分析
    2.4.2 構(gòu)造器注入
    2.4.2.1 構(gòu)造器注入的使用方法
    2.4.2.2 構(gòu)造器注入源碼分析
    2.4.3 注解注入
    2.4.3.1 @Autowired
    2.4.3.2 @Resouce
  3. 總結(jié)

1. 前言

在分析源碼之前,我們先思考幾個小問題。

  1. 到底什么是依賴注入?spring中又是如何實現(xiàn)依賴注入的?
  2. 依賴注入的方式有哪些?有哪些異同
  3. @Autowired和@Resource有哪些區(qū)別?field用@Autowired或者@Resource注入的時候可以沒有set方法嗎?@Autowired或者@Resource 注入的field修飾符可以是private嗎?如果要注入的類有多個實現(xiàn)會怎么樣?注入的field名稱和容器中配置的bean的name必須保持一致嗎?
  4. 循環(huán)依賴怎么處理?為什么不能處理基于構(gòu)造器的循環(huán)依賴?為什么可以處理基于field的循環(huán)依賴?
    那么我們就帶著這些問題,溯源spring依賴注入的內(nèi)幕。

2. spring的依賴注入

2.1 什么是依賴注入

那么到底什么是spring的依賴注入呢?再說這個概念之前我們先說下以下IOC和DI

  • IOC(Inversion Of Controller)即控制反轉(zhuǎn),意思是控制權(quán)的轉(zhuǎn)向。以前我們需要依賴的時候,我們自己會去創(chuàng)建依賴。而用了spring之后,我們需要依賴的時候,我們會去請求spring的容器,由spring容器去給我們注入依賴。
  • DI(Dependency Injection)即依賴注入,依賴注入其實是IOC在spring中的具體表現(xiàn)。
    spring的依賴注入其實是我們實例化bean時,初始化依賴并注入的過程。

2.2 依賴注入的常見方式

那么spring中常用的依賴注入方式有哪些呢?

方式 優(yōu)點 缺點
set注入 1. 便于查看依賴關(guān)系 。2. 單例模式下可以解決循環(huán)依賴 1.需要額外增加配置和set方法。2. 不能保證注入完整性
構(gòu)造器注入 1.具有set方式的優(yōu)點。2. 且可以保證注入的完整性(spring 不會把空的屬性注入到構(gòu)造器中) 1. 需要額外配置。2.需要相應的構(gòu)造器。3.無法解決循環(huán)依賴
注解注入 1. 簡潔,無需多余的方法。2. 基于field注解注入,單例模式下能解決循環(huán)依賴 1. 依賴關(guān)系不明顯。2. 如果是基于field用注解依賴注入,則不能保證變量初始化的狀態(tài)是否正確(可能注入一個空的依賴)。3.如果是基于構(gòu)造器注入,則無法解決循環(huán)依賴。

2.3 整體bean的創(chuàng)建流程

再說依賴注入之前,我們先回顧下spring 整體bean的創(chuàng)建流程,依賴注入也是創(chuàng)建bean中的一部分。spring根據(jù)不同scope創(chuàng)建bean時,要經(jīng)歷以下幾個過程
1. 處理MethodOverrides
2. 實例化的前置處理
3. 根據(jù)不同的策略實例化bean,并包裝成beanWapper
4. 提前暴露beanFactory
5. 屬性填充
6. 調(diào)用初始化方法,即各種處理器
7. 注冊銷毀相關(guān)方法

bean創(chuàng)建的流程圖

2.4 三種注入方式

直入正題,分析下三種注入方式的實現(xiàn)原理。set注入,構(gòu)造器注入,注解注入

2.4.1 set注入

set注入,顧名思義通過添加set方法進行注入。是最基礎,最原始的注入方式。

2.4.1.1 set注入的使用方法

  1. 添加set 方法
public class ServiceAImpl implements ServiceA {
    private ServiceB serviceB;
    @Override
    public void methodA() {
        serviceB.methodB();
    }

    public void setServiceB(ServiceB serviceB) {
        this.serviceB = serviceB;
    }
}

public class ServiceBImpl implements ServiceB {
    @Override
    public void methodB() {
        System.out.println("methodB");
    }
}
  1. 配置xml
    <bean id="serviceA" class="onlyspring.ioc.ServiceAImpl">
        <property name="serviceB" ref="serviceB"/>
    </bean>
    <bean id="serviceB" class="onlyspring.ioc.ServiceBImpl"/>

通過以上配置便可以正常的在被注入的類中獲取要注入的屬性了。那么set注入究竟是怎么注入的?為什么要有set方法呢?

2.4.1.2 set注入源碼分析

上面我們提到了spring創(chuàng)建bean的過程,其中set注入發(fā)生在階段5,即屬性填充時,大致流程如下:
1. 容器初始化的時候,解析配置文件得到BeanDefinition。
2. 實例化的時候,通過反射使用無參構(gòu)造器實例化bean。
3. 根據(jù)當前BeanDefinition中的PropertyValues。做屬性填充。
4. 屬性填充時依次調(diào)用BeanFactory.getBean做依賴的初始化。
5. 調(diào)用set方法設置屬性值。

set注入流程圖

1.容器初始化的時候,解析配置文件得到BeanDefinition

 //初始化容器
        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));

解析bean屬性

BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

得到List<PropertyValue> propertyValueList;

public void parsePropertyElement(Element ele, BeanDefinition bd) {
        String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
        if (!StringUtils.hasLength(propertyName)) {
            error("Tag 'property' must have a 'name' attribute", ele);
            return;
        }
        this.parseState.push(new PropertyEntry(propertyName));
        try {
            if (bd.getPropertyValues().contains(propertyName)) {
                error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
                return;
            }
            Object val = parsePropertyValue(ele, bd, propertyName);
            PropertyValue pv = new PropertyValue(propertyName, val);
            parseMetaElements(ele, pv);
            pv.setSource(extractSource(ele));
            bd.getPropertyValues().addPropertyValue(pv);
        }
        finally {
            this.parseState.pop();
        }
    }

當前步驟發(fā)生在容器初始化時,spring 會加載配置文件,并解析所有配置的bean,并放入緩存。
2. 實例化的時候,通過反射使用無參構(gòu)造器實例化bean
在步驟1中,我們完成了容器初始化的配置文件解析,那么接下來就要進行bean的創(chuàng)建bean的創(chuàng)建本身是實例化bean,并初始化的過程那么實例化要用到哪種策略(調(diào)哪個構(gòu)造函數(shù),有參的還是無參的?有參的具體調(diào)用哪個構(gòu)造方法)?源碼如下:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
        // Make sure bean class is actually resolved at this point.
        Class<?> beanClass = resolveBeanClass(mbd, beanName);

        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
        }

        if (mbd.getFactoryMethodName() != null)  {
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }

        // Shortcut when re-creating the same bean...
        boolean resolved = false;
        boolean autowireNecessary = false;
        if (args == null) {
            synchronized (mbd.constructorArgumentLock) {
                if (mbd.resolvedConstructorOrFactoryMethod != null) {
                    resolved = true;
                    autowireNecessary = mbd.constructorArgumentsResolved;
                }
            }
        }
        if (resolved) {
            if (autowireNecessary) {
                return autowireConstructor(beanName, mbd, null, null);
            }
            else {
                return instantiateBean(beanName, mbd);
            }
        }

        // Need to determine the constructor...
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors != null ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
            return autowireConstructor(beanName, mbd, ctors, args);
        }

        // No special handling: simply use no-arg constructor.
        return instantiateBean(beanName, mbd);
    }

set注入并不會走構(gòu)造器注入,所以在這里會通過反射調(diào)用無參構(gòu)造方法進行bean的實例化
3. 根據(jù)當前BeanDefinition中的PropertyValues,做屬性填充
bean實例化完成后,此時的bean僅僅是一個空的Object,各種屬性未賦值,還無法使用。那么接下來就會發(fā)生屬性的填充。set注入毫無例外也是這個時候進行的。源碼如下:

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
        PropertyValues pvs = mbd.getPropertyValues();

        if (bw == null) {
            if (!pvs.isEmpty()) {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
            }
            else {
                // Skip property population phase for null instance.
                return;
            }
        }

        // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
        // state of the bean before properties are set. This can be used, for example,
        // to support styles of field injection.
        boolean continueWithPropertyPopulation = true;

        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                        continueWithPropertyPopulation = false;
                        break;
                    }
                }
            }
        }

        if (!continueWithPropertyPopulation) {
            return;
        }

        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) {
                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);
    }

4. 屬性填充時依次調(diào)用BeanFactory.getBean做依賴的初始化。
在步驟3中,在做屬性填充的時候,發(fā)現(xiàn)有些依賴未初始化,那么此時需要做依賴初始化,依賴的初始化流程其實就是再走一遍BeanFacotry.getBean的流程。源碼如下

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
        if (pvs == null || pvs.isEmpty()) {
            return;
        }

        if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
            ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
        }

        MutablePropertyValues mpvs = null;
        List<PropertyValue> original;

        if (pvs instanceof MutablePropertyValues) {
            mpvs = (MutablePropertyValues) pvs;
            if (mpvs.isConverted()) {
                // Shortcut: use the pre-converted values as-is.
                try {
                    bw.setPropertyValues(mpvs);
                    return;
                }
                catch (BeansException ex) {
                    throw new BeanCreationException(
                            mbd.getResourceDescription(), beanName, "Error setting property values", ex);
                }
            }
            original = mpvs.getPropertyValueList();
        }
        else {
            original = Arrays.asList(pvs.getPropertyValues());
        }

        TypeConverter converter = getCustomTypeConverter();
        if (converter == null) {
            converter = bw;
        }
        BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

        // Create a deep copy, resolving any references for values.
        List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
        boolean resolveNecessary = false;
        for (PropertyValue pv : original) {
            if (pv.isConverted()) {
                deepCopy.add(pv);
            }
            else {
                String propertyName = pv.getName();
                Object originalValue = pv.getValue();
                Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
                Object convertedValue = resolvedValue;
                boolean convertible = bw.isWritableProperty(propertyName) &&
                        !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
                if (convertible) {
                    convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
                }
                // Possibly store converted value in merged bean definition,
                // in order to avoid re-conversion for every created bean instance.
                if (resolvedValue == originalValue) {
                    if (convertible) {
                        pv.setConvertedValue(convertedValue);
                    }
                    deepCopy.add(pv);
                }
                else if (convertible && originalValue instanceof TypedStringValue &&
                        !((TypedStringValue) originalValue).isDynamic() &&
                        !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
                    pv.setConvertedValue(convertedValue);
                    deepCopy.add(pv);
                }
                else {
                    resolveNecessary = true;
                    deepCopy.add(new PropertyValue(pv, convertedValue));
                }
            }
        }
        if (mpvs != null && !resolveNecessary) {
            mpvs.setConverted();
        }

        // Set our (possibly massaged) deep copy.
        try {
            bw.setPropertyValues(new MutablePropertyValues(deepCopy));
        }
        catch (BeansException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Error setting property values", ex);
        }
    }

5. 調(diào)用set方法設置屬性值
步驟4后,我們已經(jīng)初始化了相應的依賴,此時對于依賴注入最后要做的就是通過反射調(diào)用set方法進行注入。源碼如下:

try {
            bw.setPropertyValues(new MutablePropertyValues(deepCopy));
        }
        catch (BeansException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Error setting property values", ex);
        }
public void setValue(final Object object, Object valueToApply) throws Exception {
            final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?
                    ((GenericTypeAwarePropertyDescriptor) this.pd).getWriteMethodForActualAccess() :
                    this.pd.getWriteMethod());
            if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers()) && !writeMethod.isAccessible()) {
                if (System.getSecurityManager() != null) {
                    AccessController.doPrivileged(new PrivilegedAction<Object>() {
                        @Override
                        public Object run() {
                            writeMethod.setAccessible(true);
                            return null;
                        }
                    });
                }
                else {
                    writeMethod.setAccessible(true);
                }
            }
            final Object value = valueToApply;
            if (System.getSecurityManager() != null) {
                try {
                    AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                        @Override
                        public Object run() throws Exception {
                            writeMethod.invoke(object, value);
                            return null;
                        }
                    }, acc);
                }
                catch (PrivilegedActionException ex) {
                    throw ex.getException();
                }
            }
            else {
                writeMethod.invoke(getWrappedInstance(), value);
            }
        }
    }

看完set注入的源碼,我們看下如下case。
ServiceA里有個ServiceB屬性,配置如下:

<bean id="serviceA" class="example.autowired.normal.ServiceA">
    <property name="serviceB" ref="serviceB"/>
</bean>
    <bean id="serviceB" class="example.autowired.normal.ServiceB"/>

case1如下(set方法名為setSeviceB):

public class ServiceA {
    private ServiceB serviceB;

    public void setSeviceB(ServiceB serviceB) {
        this.serviceB = serviceB;
    }

    public void test(){
        System.out.println(serviceB.tx());
    }

}

case2如下(set方法名為setserviceB):

public class ServiceA {
    private ServiceB serviceB;

    public void setserviceB(ServiceB serviceB) {
        this.serviceB = serviceB;
    }

    public void test(){
        System.out.println(serviceB.tx());
    }


}

case3 如下(set方法名為setser):

public class ServiceA {
    private ServiceB serviceB;

    public void setser(ServiceB serviceB) {
        this.serviceB = serviceB;
    }

    public void test(){
        System.out.println(serviceB.tx());
    }


}

問: case1 和 case2 和 case3 哪種能夠注入呢?
答:case1 能正常注入(常規(guī)操作),case2能正常注入(WTF?),case3無法注入
解:1:一般來說spring 會在setProperty之前,解析當前類的所有public方法(不包括從父類繼承的方法)。2.然后判斷當前類是否以set或者get 或者is開頭,然后解析成PropertyDescriptor數(shù)組,且會放入緩存中,其中key 為 首字母小寫(setMethodName.substring(3)),value 就是解析到PropertyDescriptor(含有對set方法的引用)。3.set注入的時候會根據(jù)當前propertyName(xml 中配置,和類中的filedname 相同)去緩存中取對應的PropertyDescriptor,取不到就無法完成注入。所以propertyName 必須 equal 首字母小寫(setMethodName.substring(3))。


源碼如下:
解析method部分

// Apply some reflection to the current class.

            // First get an array of all the public methods at this level
            Method methodList[] = getPublicDeclaredMethods(beanClass);

            // Now analyze each method.
            for (int i = 0; i < methodList.length; i++) {
                Method method = methodList[i];
                if (method == null) {
                    continue;
                }
                // skip static methods.
                int mods = method.getModifiers();
                if (Modifier.isStatic(mods)) {
                    continue;
                }
                String name = method.getName();
                Class<?>[] argTypes = method.getParameterTypes();
                Class<?> resultType = method.getReturnType();
                int argCount = argTypes.length;
                PropertyDescriptor pd = null;

                if (name.length() <= 3 && !name.startsWith(IS_PREFIX)) {
                    // Optimization. Don't bother with invalid propertyNames.
                    continue;
                }

                try {

                    if (argCount == 0) {
                        if (name.startsWith(GET_PREFIX)) {
                            // Simple getter
                            pd = new PropertyDescriptor(this.beanClass, name.substring(3), method, null);
                        } else if (resultType == boolean.class && name.startsWith(IS_PREFIX)) {
                            // Boolean getter
                            pd = new PropertyDescriptor(this.beanClass, name.substring(2), method, null);
                        }
                    } else if (argCount == 1) {
                        if (int.class.equals(argTypes[0]) && name.startsWith(GET_PREFIX)) {
                            pd = new IndexedPropertyDescriptor(this.beanClass, name.substring(3), null, null, method, null);
                        } else if (void.class.equals(resultType) && name.startsWith(SET_PREFIX)) {
                            // Simple setter
                            pd = new PropertyDescriptor(this.beanClass, name.substring(3), null, method);
                            if (throwsException(method, PropertyVetoException.class)) {
                                pd.setConstrained(true);
                            }
                        }
                    } else if (argCount == 2) {
                            if (void.class.equals(resultType) && int.class.equals(argTypes[0]) && name.startsWith(SET_PREFIX)) {
                            pd = new IndexedPropertyDescriptor(this.beanClass, name.substring(3), null, null, null, method);
                            if (throwsException(method, PropertyVetoException.class)) {
                                pd.setConstrained(true);
                            }
                        }
                    }
                } catch (IntrospectionException ex) {
                    // This happens if a PropertyDescriptor or IndexedPropertyDescriptor
                    // constructor fins that the method violates details of the deisgn
                    // pattern, e.g. by having an empty name, or a getter returning
                    // void , or whatever.
                    pd = null;
                }

                if (pd != null) {
                    // If this class or one of its base classes is a PropertyChange
                    // source, then we assume that any properties we discover are "bound".
                    if (propertyChangeSource) {
                        pd.setBound(true);
                    }
                    addPropertyDescriptor(pd);
                }
            }

首字母轉(zhuǎn)小寫部分

PropertyDescriptor(Class<?> bean, String base, Method read, Method write) throws IntrospectionException {
        if (bean == null) {
            throw new IntrospectionException("Target Bean class is null");
        }
        setClass0(bean);
        setName(Introspector.decapitalize(base));
        setReadMethod(read);
        setWriteMethod(write);
        this.baseName = base;
    }

存放cache 部分

            PropertyDescriptor[] pds = this.beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor pd : pds) {
                if (Class.class == beanClass &&
                        ("classLoader".equals(pd.getName()) ||  "protectionDomain".equals(pd.getName()))) {
                    // Ignore Class.getClassLoader() and getProtectionDomain() methods - nobody needs to bind to those
                    continue;
                }
                if (logger.isTraceEnabled()) {
                    logger.trace("Found bean property '" + pd.getName() + "'" +
                            (pd.getPropertyType() != null ? " of type [" + pd.getPropertyType().getName() + "]" : "") +
                            (pd.getPropertyEditorClass() != null ?
                                    "; editor [" + pd.getPropertyEditorClass().getName() + "]" : ""));
                }
                pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
                this.propertyDescriptorCache.put(pd.getName(), pd);
            }

2.4.2 構(gòu)造器注入

構(gòu)造器注入,即通過構(gòu)造函數(shù)進行注入。需要在類中添加相應的構(gòu)造方法。

2.4.2.1 構(gòu)造器注入的使用方法

  1. 添加構(gòu)造函數(shù)
public class ServiceA {
    private ServiceB serviceB;

    public ServiceA(ServiceB serviceB){
        this.serviceB=serviceB;
    }

    public void test(){
        System.out.println(serviceB.tx());
    }
}

public class ServiceB {
     String tx(){
        return "ConServiceB test";
    }
}
  1. 配置xml
    <bean id="conServiceA" class="example.autowired.cons.ServiceA">
        <constructor-arg ref="conServiceB"/>
    </bean>

    <bean id="conServiceB" class="example.autowired.cons.ServiceB"/>

通過以上配置便可以通過構(gòu)造器注入了。構(gòu)造器注入與set注入的最大區(qū)別就是構(gòu)造器注入無法解決循環(huán)依賴的問題,那么構(gòu)造器注入到底是如何生效的?為什么又無法解決循環(huán)依賴呢?


2.4.2.2 構(gòu)造器注入源碼分析

上面我們提到了spring創(chuàng)建bean的過程,其中構(gòu)造器注入發(fā)生在階段3,即選擇不同的實例化策略時,大致流程如下:
1. 容器初始化的時候,解析配置文件得到BeanDefinition。
2. 實例化的時候,BeanDefinition的constructorArgumentValues不為空,決定進行構(gòu)造器注入。
3. 實例化構(gòu)造器依賴的相關(guān)屬性。
4. 調(diào)用相關(guān)構(gòu)造器進行實例化,完成構(gòu)造器注入。

構(gòu)造器注入流程圖.jpg

1.容器初始化的時候,解析配置文件得到BeanDefinition

 //初始化容器
        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));

解析bean屬性

BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

得到ConstructorArgumentValues constructorArgumentValues;

public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
        String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
        String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
        String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
        if (StringUtils.hasLength(indexAttr)) {
            try {
                int index = Integer.parseInt(indexAttr);
                if (index < 0) {
                    error("'index' cannot be lower than 0", ele);
                }
                else {
                    try {
                        this.parseState.push(new ConstructorArgumentEntry(index));
                        Object value = parsePropertyValue(ele, bd, null);
                        ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
                        if (StringUtils.hasLength(typeAttr)) {
                            valueHolder.setType(typeAttr);
                        }
                        if (StringUtils.hasLength(nameAttr)) {
                            valueHolder.setName(nameAttr);
                        }
                        valueHolder.setSource(extractSource(ele));
                        if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
                            error("Ambiguous constructor-arg entries for index " + index, ele);
                        }
                        else {
                            bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
                        }
                    }
                    finally {
                        this.parseState.pop();
                    }
                }
            }
            catch (NumberFormatException ex) {
                error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
            }
        }
        else {
            try {
                this.parseState.push(new ConstructorArgumentEntry());
                Object value = parsePropertyValue(ele, bd, null);
                ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
                if (StringUtils.hasLength(typeAttr)) {
                    valueHolder.setType(typeAttr);
                }
                if (StringUtils.hasLength(nameAttr)) {
                    valueHolder.setName(nameAttr);
                }
                valueHolder.setSource(extractSource(ele));
                bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
            }
            finally {
                this.parseState.pop();
            }
        }
    }

當前步驟發(fā)生在容器初始化時,spring 會加載配置文件,并解析所有配置的bean,并放入緩存。
2. 實例化的時候,BeanDefinition的constructorArgumentValues不為空,決定進行構(gòu)造器注入。
doCreateBean的時候先進行bean的實例化

        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }

mbd.hasConstructorArgumentValues()不為空,即配置文件中存在 constructor-arg 屬性。那么需要調(diào)用構(gòu)造器進行注入

        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors != null ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
            return autowireConstructor(beanName, mbd, ctors, args);
        }

3. 調(diào)用構(gòu)造器注入前,進行依賴的初始化。

    ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
                resolvedValues = new ConstructorArgumentValues();
                minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
    Object resolvedValue =
                        valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
                ConstructorArgumentValues.ValueHolder resolvedValueHolder =
                        new ConstructorArgumentValues.ValueHolder(resolvedValue, valueHolder.getType(), valueHolder.getName());
                resolvedValueHolder.setSource(valueHolder);
                resolvedValues.addIndexedArgumentValue(index, resolvedValueHolder);

初始化的過程其實就是getBean的過程

    Object bean = this.beanFactory.getBean(refName);
                this.beanFactory.registerDependentBean(refName, this.beanName);
                return bean;

4. 調(diào)用構(gòu)造器進行實例化。
在步驟3中,我們已經(jīng)實例化了調(diào)用構(gòu)造器所需依賴,那么接下來就可以將該參數(shù)傳給構(gòu)造器,通過反射調(diào)用構(gòu)造器進行注入了。當然調(diào)用構(gòu)造器之前有一個構(gòu)造器解析并選擇的過程,無非就是根據(jù)參數(shù)類型和參數(shù)位置已經(jīng)排序來選擇。
選擇構(gòu)造器的過程

for (Constructor<?> candidate : candidates) {
                Class<?>[] paramTypes = candidate.getParameterTypes();

                if (constructorToUse != null && argsToUse.length > paramTypes.length) {
                    // Already found greedy constructor that can be satisfied ->
                    // do not look any further, there are only less greedy constructors left.
                    break;
                }
                if (paramTypes.length < minNrOfArgs) {
                    continue;
                }

                ArgumentsHolder argsHolder;
                if (resolvedValues != null) {
                    try {
                        String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
                        if (paramNames == null) {
                            ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                            if (pnd != null) {
                                paramNames = pnd.getParameterNames(candidate);
                            }
                        }
                        argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
                                getUserDeclaredConstructor(candidate), autowiring);
                    }
                    catch (UnsatisfiedDependencyException ex) {
                        if (this.beanFactory.logger.isTraceEnabled()) {
                            this.beanFactory.logger.trace(
                                    "Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
                        }
                        // Swallow and try next constructor.
                        if (causes == null) {
                            causes = new LinkedList<UnsatisfiedDependencyException>();
                        }
                        causes.add(ex);
                        continue;
                    }
                }
                else {
                    // Explicit arguments given -> arguments length must match exactly.
                    if (paramTypes.length != explicitArgs.length) {
                        continue;
                    }
                    argsHolder = new ArgumentsHolder(explicitArgs);
                }

                int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
                        argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
                // Choose this constructor if it represents the closest match.
                if (typeDiffWeight < minTypeDiffWeight) {
                    constructorToUse = candidate;
                    argsHolderToUse = argsHolder;
                    argsToUse = argsHolder.arguments;
                    minTypeDiffWeight = typeDiffWeight;
                    ambiguousConstructors = null;
                }
                else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
                    if (ambiguousConstructors == null) {
                        ambiguousConstructors = new LinkedHashSet<Constructor<?>>();
                        ambiguousConstructors.add(constructorToUse);
                    }
                    ambiguousConstructors.add(candidate);
                }
            }

調(diào)用構(gòu)造器進行注入的過程

                beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
                        mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner,
            final Constructor<?> ctor, Object... args) {

        if (bd.getMethodOverrides().isEmpty()) {
            if (System.getSecurityManager() != null) {
                // use own privileged to change accessibility (when security is on)
                AccessController.doPrivileged(new PrivilegedAction<Object>() {
                    @Override
                    public Object run() {
                        ReflectionUtils.makeAccessible(ctor);
                        return null;
                    }
                });
            }
            return BeanUtils.instantiateClass(ctor, args);
        }
        else {
            return instantiateWithMethodInjection(bd, beanName, owner, ctor, args);
        }
    }

2.4.3 注解注入

注解注入,顧名思義就是通過注解進行注入。這種注入方式不用做xml配置,是我們最常使用的注入方式。而最常用的注入的注解無非說就是@Autowired和@Resource。

2.4.3.1 @Autowired

2.4.3.1.1 @Autowired使用方法
  1. 注入屬性
public class ServiceA {
    @Autowired
    ServiceB serviceB;
    public String test(){
       return serviceB.tb();
    }
}

public interface ServiceB {
    String tb();
}

public class ServiceBImplOne implements ServiceB{
    @Override
    public String tb() {
        return "ServiceBImplOne";
    }
}
  1. 配置xml
   <context:annotation-config/>
    <bean id="sa" class="example.autowired.auto.ServiceA"/>
    <bean id="s1" class="example.autowired.auto.ServiceBImplOne"></bean>

或者配置包自動掃描

<context:component-scan base-package="example.*"/>

@Component
public class ServiceA {
    @Autowired
    ServiceB serviceB;
    public String test(){
       return serviceB.tb();
    }
}

@Component
public class ServiceBImplOne implements ServiceB{
    @Override
    public String tb() {
        return "ServiceBImplOne";
    }
}

值得注意的是,以上兩種都可以讓當前bean受spring管理。且使用的時候不能再使用BeanFactory,而是要使用ApplicationContext,因為BeanFactory初始化容器的時候并不會提取并注冊BeanPostProcessor,而注解注入依賴的就是BeanPostProcessor,包括我們熟知的aop,Transaction都是基于各種BeanPostProcessor實現(xiàn)的,這也是我們在前幾篇文章中說的,如果要實使用這些功能,就必須用ApplicationContext的原因。當然你也可以選擇使用BeanPostProcessor,然后自己去注冊BeanPostProcessor,但是便捷性不如ApplicationContext。

public static void main(String[] args) {
        //初始化容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config.xml");
        ServiceA serviceA = (ServiceA) applicationContext.getBean("sa");
        System.out.println(serviceA.test());
    }
2.4.3.1.2 @Autowired源碼

上面我們提到了spring 創(chuàng)建bean的流程,@Autowired生效的過程大致分為兩步,解析InjectionMetadata,注入屬性。其中解析InjectionMetadata 發(fā)生在步驟3和步驟4之間,applyMergedBeanDefinitionPostProcessors被調(diào)用時。而注入屬性則發(fā)生在步驟5,屬性填充時。大致流程如下:
1. 容器初始化的時候,解析配置文件得到BeanDefinition。
2. 創(chuàng)建bean的時候,調(diào)用無參構(gòu)造方法實例化bean。
3. 調(diào)用applyMergedBeanDefinitionPostProcessors 動態(tài)改變RootBeanDefinition,且調(diào)用AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition,解析得到InjectionMetadata,并將其放入緩存。更新RootBeanDefinition的externallyManagedConfigMembers屬性。
4. 屬性填充時,調(diào)用AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues做屬性填充。

autowired.jpg

1.容器初始化的時候,解析配置文件得到BeanDefinition

 //初始化容器
        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));

解析bean屬性,得到BeanDefinition

BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

當前步驟發(fā)生在容器初始化時,spring 會加載配置文件,并解析所有配置的bean,并放入緩存。
2. 創(chuàng)建bean的時候,調(diào)用無參構(gòu)造方法實例化bean。

if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        // Need to determine the constructor...
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors != null ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
            return autowireConstructor(beanName, mbd, ctors, args);
        }

        // No special handling: simply use no-arg constructor.
        return instantiateBean(beanName, mbd);
            else {
                beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
            }
            BeanWrapper bw = new BeanWrapperImpl(beanInstance);
            initBeanWrapper(bw);
            return bw;

3. 解析InjectionMetadata。

synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                mbd.postProcessed = true;
            }
        }

調(diào)用AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition 解析InjectionMetadata。

protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof MergedBeanDefinitionPostProcessor) {
                MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
                bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
            }
        }
    }
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        if (beanType != null) {
            InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
            metadata.checkConfigMembers(beanDefinition);
        }
    }
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
        // Fall back to class name as cache key, for backwards compatibility with custom callers.
        String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
        // Quick check on the concurrent map first, with minimal locking.
        InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
        if (InjectionMetadata.needsRefresh(metadata, clazz)) {
            synchronized (this.injectionMetadataCache) {
                metadata = this.injectionMetadataCache.get(cacheKey);
                if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                    if (metadata != null) {
                        metadata.clear(pvs);
                    }
                    try {
                        metadata = buildAutowiringMetadata(clazz);
                        this.injectionMetadataCache.put(cacheKey, metadata);
                    }
                    catch (NoClassDefFoundError err) {
                        throw new IllegalStateException("Failed to introspect bean class [" + clazz.getName() +
                                "] for autowiring metadata: could not find class that it depends on", err);
                    }
                }
            }
        }
        return metadata;
    }
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
        LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
        Class<?> targetClass = clazz;

        do {
            final LinkedList<InjectionMetadata.InjectedElement> currElements =
                    new LinkedList<InjectionMetadata.InjectedElement>();

            ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
                @Override
                public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
                    AnnotationAttributes ann = findAutowiredAnnotation(field);
                    if (ann != null) {
                        if (Modifier.isStatic(field.getModifiers())) {
                            if (logger.isWarnEnabled()) {
                                logger.warn("Autowired annotation is not supported on static fields: " + field);
                            }
                            return;
                        }
                        boolean required = determineRequiredStatus(ann);
                        currElements.add(new AutowiredFieldElement(field, required));
                    }
                }
            });

            ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() {
                @Override
                public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
                    Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
                    if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                        return;
                    }
                    AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
                    if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                        if (Modifier.isStatic(method.getModifiers())) {
                            if (logger.isWarnEnabled()) {
                                logger.warn("Autowired annotation is not supported on static methods: " + method);
                            }
                            return;
                        }
                        if (method.getParameterTypes().length == 0) {
                            if (logger.isWarnEnabled()) {
                                logger.warn("Autowired annotation should only be used on methods with parameters: " +
                                        method);
                            }
                        }
                        boolean required = determineRequiredStatus(ann);
                        PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                        currElements.add(new AutowiredMethodElement(method, required, pd));
                    }
                }
            });

            elements.addAll(0, currElements);
            targetClass = targetClass.getSuperclass();
        }
        while (targetClass != null && targetClass != Object.class);

        return new InjectionMetadata(clazz, elements);
    }

其中解析InjectionMetadata的方式為:利用反射遍歷當前class的field和method,如果發(fā)現(xiàn)出現(xiàn)@Autowired,則將其解析為InjectionMetadata。并將InjectionMetadata 放入緩存中,其中緩存的key 為beanName,值為InjectionMetadata。

4. 調(diào)用InjectionMetadata.inject做屬性注入
開始填充屬性

populateBean(beanName, mbd, instanceWrapper);
    if (hasInstAwareBpps || needsDepCheck) {
            PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            if (hasInstAwareBpps) {
                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);
            }
        }

調(diào)用AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues做屬性填充

public PropertyValues postProcessPropertyValues(
            PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {

        InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
        try {
            metadata.inject(bean, beanName, pvs);
        }
        catch (BeanCreationException ex) {
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
        }
        return pvs;
    }

初始化相關(guān)依賴,將field設置為可訪問,為field 賦值。

        protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
            Field field = (Field) this.member;
            Object value;
            if (this.cached) {
                value = resolvedCachedArgument(beanName, this.cachedFieldValue);
            }
            else {
                DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
                desc.setContainingClass(bean.getClass());
                Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
                TypeConverter typeConverter = beanFactory.getTypeConverter();
                try {
                    value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
                }
                catch (BeansException ex) {
                    throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
                }
                synchronized (this) {
                    if (!this.cached) {
                        if (value != null || this.required) {
                            this.cachedFieldValue = desc;
                            registerDependentBeans(beanName, autowiredBeanNames);
                            if (autowiredBeanNames.size() == 1) {
                                String autowiredBeanName = autowiredBeanNames.iterator().next();
                                if (beanFactory.containsBean(autowiredBeanName)) {
                                    if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
                                        this.cachedFieldValue = new ShortcutDependencyDescriptor(
                                                desc, autowiredBeanName, field.getType());
                                    }
                                }
                            }
                        }
                        else {
                            this.cachedFieldValue = null;
                        }
                        this.cached = true;
                    }
                }
            }
            if (value != null) {
                ReflectionUtils.makeAccessible(field);
                field.set(bean, value);
            }
        }
    }

分析了Autowired的源碼后,我們來看下思考如下case
case1 私有屬性能否注入:


public class ServiceA {
    @Autowired
    private  ServiceB serviceB;
    public String test(){
       return serviceB.tb();
    }
}

public class ServiceBImplOne implements ServiceB{
    @Override
    public String tb() {
        return "ServiceBImplOne";
    }
}
    <bean id="sa" class="example.autowired.auto.ServiceA"/>
    <bean id="s1" class="example.autowired.auto.ServiceBImplOne"/>

case2 兩個同類型的bean 能否注入:

public class ServiceA {
    @Autowired
    private  ServiceB serviceB;
    public String test(){
       return serviceB.tb();
    }
}
public class ServiceBImplOne implements ServiceB{
    @Override
    public String tb() {
        return "ServiceBImplOne";
    }
}
public class ServiceBImplTwo implements ServiceB{
    @Override
    public String tb() {
        return "ServiceBImplTwo";
    }
}
    <bean id="sa" class="example.autowired.auto.ServiceA"/>
    <bean id="s1" class="example.autowired.auto.ServiceBImplOne"/>
    <bean id="s2" class="example.autowired.auto.ServiceBImplTwo"/>

case3 兩個相同類型的 bean,且fieldName.equal(beanName):

public class ServiceA {
    @Autowired
    private  ServiceB s1;
    public String test(){
       return s1.tb();
    }
}
public class ServiceBImplOne implements ServiceB{
    @Override
    public String tb() {
        return "ServiceBImplOne";
    }
}
public class ServiceBImplTwo implements ServiceB{
    @Override
    public String tb() {
        return "ServiceBImplTwo";
    }
}
   <bean id="sa" class="example.autowired.auto.ServiceA"/>
    <bean id="s1" class="example.autowired.auto.ServiceBImplOne"/>
    <bean id="s2" class="example.autowired.auto.ServiceBImplTwo"/>

問:case1 能正確注入嗎?
答:能。因為注入的時候無論filed是否私有,都會利用反射將其置為可訪問,從而直接為其賦值
問:case2 能正確注入嗎?
答:不能。因為@Autowired注入的時候,初始化依賴的時候,先是根據(jù)類型去查,查到兩個同類型的bean,再根據(jù)fieldName去匹配,如果beanName.equal(fieldName),則取命中的bean注入,否則報錯NoUniqueBeanDefinitionException。
問:case3 能正確注入嗎?
答:能。
查詢依賴相關(guān)源碼如下:

            Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
            if (matchingBeans.isEmpty()) {
                if (isRequired(descriptor)) {
                    raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
                }
                return null;
            }

查找所有example.autowired.auto.ServiceB 類型的bean,并且實例化

protected Map<String, Object> findAutowireCandidates(
            String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {

        String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                this, requiredType, true, descriptor.isEager());
        Map<String, Object> result = new LinkedHashMap<String, Object>(candidateNames.length);
        for (Class<?> autowiringType : this.resolvableDependencies.keySet()) {
            if (autowiringType.isAssignableFrom(requiredType)) {
                Object autowiringValue = this.resolvableDependencies.get(autowiringType);
                autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
                if (requiredType.isInstance(autowiringValue)) {
                    result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
                    break;
                }
            }
        }
        for (String candidate : candidateNames) {
            if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
                addCandidateEntry(result, candidate, descriptor, requiredType);
            }
        }
        if (result.isEmpty() && !indicatesMultipleBeans(requiredType)) {
            // Consider fallback matches if the first pass failed to find anything...
            DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
            for (String candidate : candidateNames) {
                if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor)) {
                    addCandidateEntry(result, candidate, descriptor, requiredType);
                }
            }
            if (result.isEmpty()) {
                // Consider self references as a final pass...
                // but in the case of a dependency collection, not the very same bean itself.
                for (String candidate : candidateNames) {
                    if (isSelfReference(beanName, candidate) &&
                            (!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
                            isAutowireCandidate(candidate, fallbackDescriptor)) {
                        addCandidateEntry(result, candidate, descriptor, requiredType);
                    }
                }
            }
        }
        return result;
    }

根據(jù)查找結(jié)果進行處理。如果查找的結(jié)果數(shù)量為1,則直接取查找到的bean實例做為待注入的參數(shù)值。如果查找的結(jié)果數(shù)量>1,則繼續(xù)根據(jù)filedName做完全匹配,如果未匹配到結(jié)果則報錯,如果匹配到結(jié)果,則直接取查找到的bean實例做為待注入的參數(shù)值

if (matchingBeans.size() > 1) {
                autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
                if (autowiredBeanName == null) {
                    if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
                        return descriptor.resolveNotUnique(type, matchingBeans);
                    }
                    else {
                        // In case of an optional Collection/Map, silently ignore a non-unique case:
                        // possibly it was meant to be an empty collection of multiple regular beans
                        // (before 4.3 in particular when we didn't even look for collection beans).
                        return null;
                    }
                }
                instanceCandidate = matchingBeans.get(autowiredBeanName);
            }
            else {
                // We have exactly one match.
                Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
                autowiredBeanName = entry.getKey();
                instanceCandidate = entry.getValue();
            }

流程圖如下:


Autowired 屬性查找的過程.jpg
2.4.3.2 @Resouce

上面我們看了@Autowired的源碼,接下來我們分析下@Resource的源碼。@Resource的裝配流程跟@Autowired,不同的地方在于依賴的查找策略上。大致流程如下:
1. 容器初始化的時候,解析配置文件得到BeanDefinition。
2. 創(chuàng)建bean的時候,調(diào)用無參構(gòu)造方法實例化bean。
3. 調(diào)用applyMergedBeanDefinitionPostProcessors 動態(tài)改變RootBeanDefinition,且調(diào)用CommonAnnotationBeanPostProcessor.postProcessMergedBeanDefinition,解析得到InjectionMetadata,并將其放入緩存。更新RootBeanDefinition的externallyManagedConfigMembers屬性。
4. 屬性填充時,調(diào)用CommonAnnotationBeanPostProcessor.postProcessPropertyValues做屬性填充。


可以看到,整個裝配的套路跟@Autowired是類似的,不同之處在于調(diào)用不同的BeanPostProcessor,從而實現(xiàn)不同的依賴查找策略。那么這個依賴查找策略究竟有什么不同呢?或許我們能從源碼里找到不同,這里我們重點看下依賴查找的過程。

  1. 屬性填充時,調(diào)用InjectionMetadata.inject做屬性注入
    public void inject(Object target, String beanName, PropertyValues pvs) throws Throwable {
        Collection<InjectedElement> elementsToIterate =
                (this.checkedElements != null ? this.checkedElements : this.injectedElements);
        if (!elementsToIterate.isEmpty()) {
            boolean debug = logger.isDebugEnabled();
            for (InjectedElement element : elementsToIterate) {
                if (debug) {
                    logger.debug("Processing injected element of bean '" + beanName + "': " + element);
                }
                element.inject(target, beanName, pvs);
            }
        }
    }
  1. 通過反射為屬性賦值時,獲取屬性值
    protected void inject(Object target, String requestingBeanName, PropertyValues pvs) throws Throwable {
            if (this.isField) {
                Field field = (Field) this.member;
                ReflectionUtils.makeAccessible(field);
                field.set(target, getResourceToInject(target, requestingBeanName));
            }
            else {
                if (checkPropertySkipping(pvs)) {
                    return;
                }
                try {
                    Method method = (Method) this.member;
                    ReflectionUtils.makeAccessible(method);
                    method.invoke(target, getResourceToInject(target, requestingBeanName));
                }
                catch (InvocationTargetException ex) {
                    throw ex.getTargetException();
                }
            }
        }
  1. 如果指定的name 屬性,那么根據(jù)name 和類型去查找bean。
    protected Object autowireResource(BeanFactory factory, LookupElement element, String requestingBeanName)
            throws BeansException {

        Object resource;
        Set<String> autowiredBeanNames;
        String name = element.name;

        if (this.fallbackToDefaultTypeMatch && element.isDefaultName &&
                factory instanceof AutowireCapableBeanFactory && !factory.containsBean(name)) {
            autowiredBeanNames = new LinkedHashSet<String>();
            resource = ((AutowireCapableBeanFactory) factory).resolveDependency(
                    element.getDependencyDescriptor(), requestingBeanName, autowiredBeanNames, null);
        }
        else {
            resource = factory.getBean(name, element.lookupType);
            autowiredBeanNames = Collections.singleton(name);
        }

        if (factory instanceof ConfigurableBeanFactory) {
            ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;
            for (String autowiredBeanName : autowiredBeanNames) {
                if (beanFactory.containsBean(autowiredBeanName)) {
                    beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
                }
            }
        }

        return resource;
    }
  1. 未指定name屬性,則使用autowired 一樣的查找策略。
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
            if (matchingBeans.isEmpty()) {
                if (isRequired(descriptor)) {
                    raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
                }
                return null;
            }

            String autowiredBeanName;
            Object instanceCandidate;

            if (matchingBeans.size() > 1) {
                autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
                if (autowiredBeanName == null) {
                    if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
                        return descriptor.resolveNotUnique(type, matchingBeans);
                    }
                    else {
                        // In case of an optional Collection/Map, silently ignore a non-unique case:
                        // possibly it was meant to be an empty collection of multiple regular beans
                        // (before 4.3 in particular when we didn't even look for collection beans).
                        return null;
                    }
                }
                instanceCandidate = matchingBeans.get(autowiredBeanName);
            }
            else {
                // We have exactly one match.
                Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
                autowiredBeanName = entry.getKey();
                instanceCandidate = entry.getValue();
            }

可以看到@Autowired的區(qū)別主要在于是否指定name,以及 type 屬性。

注解 查找過程 不同點
@Autowired 1. 根據(jù)class,查找所有類型的bean。
2. 查找不到,根據(jù)required屬性,決定是否拋出NoSuchBeanDefinitionException。
3. 查找的到,且只查找一個,則使用該bean做屬性注入。
4. 查找到不止一個,則根據(jù)條件做精確篩選唯一,未篩選到拋出NoUniqueBeanDefinitionException。
5. 篩選到唯一,則使用唯一的bean做屬性注入。
不會根據(jù)name做查找。
@Resource 1. 如果配置了name,根據(jù)name查找特定name和type類型(未指定則使用默認type)的bean做屬性注入。
2. 如果未配置name,根據(jù)class,查找所有類型的bean。
3. 查找不到,根據(jù)required屬性,決定是否拋出NoSuchBeanDefinitionException。
4. 查找的到,且只查找一個,則使用該bean做屬性注入。
5. 查找到不止一個,則根據(jù)條件做精確篩選唯一,未篩選到拋出NoUniqueBeanDefinitionException。
6. 篩選到唯一,則使用唯一的bean做屬性注入。
先根據(jù)name做查找,找不到則使用autowired一樣的策略。

3 總結(jié)

本篇文章中,總結(jié)了spring 幾種依賴注入的方式,并著重分析了@Autowired和@Resource的區(qū)別。雖然大部分情況下,@Autowired和@Resource都基本一致。但是本著打破砂鍋問到底的煩人精神,我們還是淺析了部分源碼。希望本篇文章能在各位同學被面試官靈魂拷問的時候起到幫助。

下一篇文章,我們會分析spring的核心容器,ApplicationContext,我們下篇文章見。。。。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容