spring源码系列-从@Autowired与@Resource异同中看依赖注入

上一篇文章spring源码系列-Bean的创建流程中,我们抽丝剥茧的去分析bean的创建流程,终于揭开了spring创建bean的“黑幕”,我们对spring中bean的创建流程有了大概的了解。但是我们很少会直接用BeanFactory.getBean的方式去获取进而使用Bean,常规操作一般是基于注解注入,如@Autowired,@Resource等。那么这些注解是如何做依赖注入的?幕后又有哪些操作,是“人性的扭曲,还是道德的沦丧”,下面我们一起走进依赖注入(IOC/DI)的世界。本文可以分为以下几个板块

  1. 前言
  2. spring的依赖注入
    2.1 什么是依赖注入
    2.2 依赖注入的常见方式
    2.3 整体bean的创建流程
    2.4 三种注入方式
    2.4.1 set注入
    2.4.1.1 set注入的使用方法
    2.4.1.2 set注入源码分析
    2.4.2 构造器注入
    2.4.2.1 构造器注入的使用方法
    2.4.2.2 构造器注入源码分析
    2.4.3 注解注入
    2.4.3.1 @Autowired
    2.4.3.2 @Resouce
  3. 总结

1. 前言

在分析源码之前,我们先思考几个小问题。

  1. 到底什么是依赖注入?spring中又是如何实现依赖注入的?
  2. 依赖注入的方式有哪些?有哪些异同
  3. @Autowired和@Resource有哪些区别?field用@Autowired或者@Resource注入的时候可以没有set方法吗?@Autowired或者@Resource 注入的field修饰符可以是private吗?如果要注入的类有多个实现会怎么样?注入的field名称和容器中配置的bean的name必须保持一致吗?
  4. 循环依赖怎么处理?为什么不能处理基于构造器的循环依赖?为什么可以处理基于field的循环依赖?
    那么我们就带着这些问题,溯源spring依赖注入的内幕。

2. spring的依赖注入

2.1 什么是依赖注入

那么到底什么是spring的依赖注入呢?再说这个概念之前我们先说下以下IOC和DI

  • IOC(Inversion Of Controller)即控制反转,意思是控制权的转向。以前我们需要依赖的时候,我们自己会去创建依赖。而用了spring之后,我们需要依赖的时候,我们会去请求spring的容器,由spring容器去给我们注入依赖
  • DI(Dependency Injection)即依赖注入,依赖注入其实是IOC在spring中的具体表现
    spring的依赖注入其实是我们实例化bean时,初始化依赖并注入的过程。

2.2 依赖注入的常见方式

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

方式 优点 缺点
set注入 1. 便于查看依赖关系 。2. 单例模式下可以解决循环依赖 1.需要额外增加配置和set方法。2. 不能保证注入完整性
构造器注入 1.具有set方式的优点。2. 且可以保证注入的完整性(spring 不会把空的属性注入到构造器中) 1. 需要额外配置。2.需要相应的构造器。3.无法解决循环依赖
注解注入 1. 简洁,无需多余的方法。2. 基于field注解注入,单例模式下能解决循环依赖 1. 依赖关系不明显。2. 如果是基于field用注解依赖注入,则不能保证变量初始化的状态是否正确(可能注入一个空的依赖)。3.如果是基于构造器注入,则无法解决循环依赖。

2.3 整体bean的创建流程

再说依赖注入之前,我们先回顾下spring 整体bean的创建流程,依赖注入也是创建bean中的一部分。spring根据不同scope创建bean时,要经历以下几个过程
1. 处理MethodOverrides
2. 实例化的前置处理
3. 根据不同的策略实例化bean,并包装成beanWapper
4. 提前暴露beanFactory
5. 属性填充
6. 调用初始化方法,即各种处理器
7. 注册销毁相关方法

bean创建的流程图

2.4 三种注入方式

直入正题,分析下三种注入方式的实现原理。set注入,构造器注入,注解注入

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创建bean的过程,其中set注入发生在阶段5,即属性填充时,大致流程如下:
1. 容器初始化的时候,解析配置文件得到BeanDefinition。
2. 实例化的时候,通过反射使用无参构造器实例化bean。
3. 根据当前BeanDefinition中的PropertyValues。做属性填充。
4. 属性填充时依次调用BeanFactory.getBean做依赖的初始化。
5. 调用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();
        }
    }

当前步骤发生在容器初始化时,spring 会加载配置文件,并解析所有配置的bean,并放入缓存。
2. 实例化的时候,通过反射使用无参构造器实例化bean
在步骤1中,我们完成了容器初始化的配置文件解析,那么接下来就要进行bean的创建bean的创建本身是实例化bean,并初始化的过程那么实例化要用到哪种策略(调哪个构造函数,有参的还是无参的?有参的具体调用哪个构造方法)?源码如下:

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注入并不会走构造器注入,所以在这里会通过反射调用无参构造方法进行bean的实例化
3. 根据当前BeanDefinition中的PropertyValues,做属性填充
bean实例化完成后,此时的bean仅仅是一个空的Object,各种属性未赋值,还无法使用。那么接下来就会发生属性的填充。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. 属性填充时依次调用BeanFactory.getBean做依赖的初始化。
在步骤3中,在做属性填充的时候,发现有些依赖未初始化,那么此时需要做依赖初始化依赖的初始化流程其实就是再走一遍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. 调用set方法设置属性值
步骤4后,我们已经初始化了相应的依赖,此时对于依赖注入最后要做的就是通过反射调用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 能正常注入(常规操作),case2能正常注入(WTF?),case3无法注入
解:1:一般来说spring 会在setProperty之前,解析当前类的所有public方法(不包括从父类继承的方法)。2.然后判断当前类是否以set或者get 或者is开头,然后解析成PropertyDescriptor数组,且会放入缓存中,其中key 为 首字母小写(setMethodName.substring(3)),value 就是解析到PropertyDescriptor(含有对set方法的引用)。3.set注入的时候会根据当前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);
                }
            }

首字母转小写部分

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 构造器注入

构造器注入,即通过构造函数进行注入。需要在类中添加相应的构造方法。

2.4.2.1 构造器注入的使用方法

  1. 添加构造函数
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"/>

通过以上配置便可以通过构造器注入了。构造器注入与set注入的最大区别就是构造器注入无法解决循环依赖的问题,那么构造器注入到底是如何生效的?为什么又无法解决循环依赖呢?


2.4.2.2 构造器注入源码分析

上面我们提到了spring创建bean的过程,其中构造器注入发生在阶段3,即选择不同的实例化策略时,大致流程如下:
1. 容器初始化的时候,解析配置文件得到BeanDefinition。
2. 实例化的时候,BeanDefinition的constructorArgumentValues不为空,决定进行构造器注入。
3. 实例化构造器依赖的相关属性。
4. 调用相关构造器进行实例化,完成构造器注入。

构造器注入流程图.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();
            }
        }
    }

当前步骤发生在容器初始化时,spring 会加载配置文件,并解析所有配置的bean,并放入缓存。
2. 实例化的时候,BeanDefinition的constructorArgumentValues不为空,决定进行构造器注入。
doCreateBean的时候先进行bean的实例化

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

mbd.hasConstructorArgumentValues()不为空,即配置文件中存在 constructor-arg 属性。那么需要调用构造器进行注入

        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. 调用构造器注入前,进行依赖的初始化。

    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. 调用构造器进行实例化。
在步骤3中,我们已经实例化了调用构造器所需依赖,那么接下来就可以将该参数传给构造器,通过反射调用构造器进行注入了。当然调用构造器之前有一个构造器解析并选择的过程,无非就是根据参数类型和参数位置已经排序来选择
选择构造器的过程

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

调用构造器进行注入的过程

                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实现的,这也是我们在前几篇文章中说的,如果要实使用这些功能,就必须用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 创建bean的流程,@Autowired生效的过程大致分为两步,解析InjectionMetadata,注入属性。其中解析InjectionMetadata 发生在步骤3和步骤4之间,applyMergedBeanDefinitionPostProcessors被调用时。而注入属性则发生在步骤5,属性填充时。大致流程如下:
1. 容器初始化的时候,解析配置文件得到BeanDefinition。
2. 创建bean的时候,调用无参构造方法实例化bean。
3. 调用applyMergedBeanDefinitionPostProcessors 动态改变RootBeanDefinition,且调用AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition,解析得到InjectionMetadata,并将其放入缓存。更新RootBeanDefinition的externallyManagedConfigMembers属性。
4. 属性填充时,调用AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues做属性填充。

autowired.jpg

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

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

解析bean属性,得到BeanDefinition

BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

当前步骤发生在容器初始化时,spring 会加载配置文件,并解析所有配置的bean,并放入缓存。
2. 创建bean的时候,调用无参构造方法实例化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;
            }
        }

调用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,如果发现出现@Autowired,则将其解析为InjectionMetadata。并将InjectionMetadata 放入缓存中,其中缓存的key 为beanName,值为InjectionMetadata。

4. 调用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);
            }
        }

调用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;
    }

初始化相关依赖,将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注入的时候,初始化依赖的时候,先是根据类型去查,查到两个同类型的bean,再根据fieldName去匹配,如果beanName.equal(fieldName),则取命中的bean注入,否则报错NoUniqueBeanDefinitionException
问:case3 能正确注入吗?
答:能。
查询依赖相关源码如下:

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

根据查找结果进行处理。如果查找的结果数量为1,则直接取查找到的bean实例做为待注入的参数值。如果查找的结果数量>1,则继续根据filedName做完全匹配,如果未匹配到结果则报错,如果匹配到结果,则直接取查找到的bean实例做为待注入的参数值

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. 创建bean的时候,调用无参构造方法实例化bean。
3. 调用applyMergedBeanDefinitionPostProcessors 动态改变RootBeanDefinition,且调用CommonAnnotationBeanPostProcessor.postProcessMergedBeanDefinition,解析得到InjectionMetadata,并将其放入缓存。更新RootBeanDefinition的externallyManagedConfigMembers属性。
4. 属性填充时,调用CommonAnnotationBeanPostProcessor.postProcessPropertyValues做属性填充。


可以看到,整个装配的套路跟@Autowired是类似的,不同之处在于调用不同的BeanPostProcessor,从而实现不同的依赖查找策略。那么这个依赖查找策略究竟有什么不同呢?或许我们能从源码里找到不同,这里我们重点看下依赖查找的过程。

  1. 属性填充时,调用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 属性,那么根据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的区别主要在于是否指定name,以及 type 属性。

注解 查找过程 不同点
@Autowired 1. 根据class,查找所有类型的bean。
2. 查找不到,根据required属性,决定是否抛出NoSuchBeanDefinitionException。
3. 查找的到,且只查找一个,则使用该bean做属性注入。
4. 查找到不止一个,则根据条件做精确筛选唯一,未筛选到抛出NoUniqueBeanDefinitionException。
5. 筛选到唯一,则使用唯一的bean做属性注入。
不会根据name做查找。
@Resource 1. 如果配置了name,根据name查找特定name和type类型(未指定则使用默认type)的bean做属性注入。
2. 如果未配置name,根据class,查找所有类型的bean。
3. 查找不到,根据required属性,决定是否抛出NoSuchBeanDefinitionException。
4. 查找的到,且只查找一个,则使用该bean做属性注入。
5. 查找到不止一个,则根据条件做精确筛选唯一,未筛选到抛出NoUniqueBeanDefinitionException。
6. 筛选到唯一,则使用唯一的bean做属性注入。
先根据name做查找,找不到则使用autowired一样的策略。

3 总结

本篇文章中,总结了spring 几种依赖注入的方式,并着重分析了@Autowired和@Resource的区别。虽然大部分情况下,@Autowired和@Resource都基本一致。但是本着打破砂锅问到底的烦人精神,我们还是浅析了部分源码。希望本篇文章能在各位同学被面试官灵魂拷问的时候起到帮助。

下一篇文章,我们会分析spring的核心容器,ApplicationContext,我们下篇文章见。。。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容