Spring Bean 装配

在Spring中装配Bean有以下三种常见的方式:

1、在XML中进行显示配置;
2、在Java代码中显示配置;
3、隐式的Bean发现机制和自动装配;

在现实的工作中,这 3 种方式都会被用到
1、通过隐式 Bean 的发现机制和自动装配的原则。基于约定由于配置的原则,这种方式应该是最优先的。
优点: 配置一次、简单、灵活。

2、Java 接口和类中配置实现配置。
优点: 代码和配置在一起,维护成本低。

3、XML中进行显示配置
优点:简单易懂(当然,特别是对于新手)
不足: 配置繁琐、配置和代码分离,可读性不太好。

Spring支持5种方式自动装配Bean

自动装配模式 解释 备注
no 不自动装配,通过“ref”属性手动设定。
byName 根据Property的Name自动装配,如果一个bean的name,和另一个bean中的Property的name相同,则自动装配这个bean到Property中。
byType 根据Property的数据类型(Type)自动装配,如果一个bean的数据类型,兼容另一个bean中Property的数据类型,则自动装配。
constructor 根据构造函数参数的数据类型,进行byType模式的自动装配。
autodetect 如果发现默认的构造函数,用constructor模式,否则,用byType模式。 spring 3.0及以上版本废弃

spring-beans.xsd

	<xsd:attribute name="autowire" default="default">
		<xsd:annotation>
			<xsd:documentation><![CDATA[
Controls whether bean properties are "autowired".
This is an automagical process in which bean references don't need
to be coded explicitly in the XML bean definition file, but rather the
Spring container works out dependencies. The effective default is "no".

There are 4 modes:

1. "no"
The traditional Spring default. No automagical wiring. Bean references
must be defined in the XML file via the <ref/> element (or "ref"
attribute). We recommend this in most cases as it makes documentation
more explicit.

Note that this default mode also allows for annotation-driven autowiring,
if activated. "no" refers to externally driven autowiring only, not
affecting any autowiring demands that the bean class itself expresses.

2. "byName"
Autowiring by property name. If a bean of class Cat exposes a "dog"
property, Spring will try to set this to the value of the bean "dog"
in the current container. If there is no matching bean by name, nothing
special happens.

3. "byType"
Autowiring if there is exactly one bean of the property type in the
container. If there is more than one, a fatal error is raised, and
you cannot use byType autowiring for that bean. If there is none,
nothing special happens.

4. "constructor"
Analogous to "byType" for constructor arguments. If there is not exactly
one bean of the constructor argument type in the bean factory, a fatal
error is raised.

Note that explicit dependencies, i.e. "property" and "constructor-arg"
elements, always override autowiring.

Note: This attribute will not be inherited by child bean definitions.
Hence, it needs to be specified per concrete bean definition. It can be
shared through the 'default-autowire' attribute at the 'beans' level
and potentially inherited from outer 'beans' defaults in case of nested
'beans' sections (e.g. with different profiles).
			]]></xsd:documentation>
		</xsd:annotation>
		<xsd:simpleType>
			<xsd:restriction base="xsd:NMTOKEN">
				<xsd:enumeration value="default"/>
				<xsd:enumeration value="no"/>
				<xsd:enumeration value="byName"/>
				<xsd:enumeration value="byType"/>
				<xsd:enumeration value="constructor"/>
			</xsd:restriction>
		</xsd:simpleType>
	</xsd:attribute>

autodetect 在3.0及以上版本弃用了
autowire=”autodetect” its property is possible in Spring?
spring-beans-2.5.xsd

Spring装配示例

在XML中进行显示配置

在Java代码中显示配置

隐式的Bean

自动装配

1、;
2、;
3、隐式的Bean发现机制和自动装配;

装配源码解读

Spring Bean属性注入源码解读

源码整体处理流程

AbstractAutowireCapableBeanFactory::populateBean()

populateBean

/**
  * Populate the bean instance in the given BeanWrapper with the property values
  * from the bean definition.
  * @param beanName the name of the bean
  * @param mbd the bean definition for the bean
  * @param bw the BeanWrapper with bean instance
  */
@SuppressWarnings("deprecation")  // for postProcessPropertyValues
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
  if (bw == null) {
    if (mbd.hasPropertyValues()) {
      throw new BeanCreationException(
          mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
    }
    else {
      // Skip property population phase for null instance.
      return;
    }
  }

  // 让任何 InstantiationAware BeanPostProcessors 有机会在设置属性之前修改 bean 的状态。 例如,这可以用于支持字段注入的样式。
  // 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()) {
	// BeanPostProcessor 各种扩展点
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof InstantiationAwareBeanPostProcessor) {
        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
        // 在实例化后处理 扩展点
        if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
          continueWithPropertyPopulation = false;
          break;
        }
      }
    }
  }

  // 如果不需要属性注入,返回
  if (!continueWithPropertyPopulation) {
    return;
  }

  PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

  if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
    MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
    // autowirte_by_name 通过名字找到所有属性值 
    // Add property values based on autowire by name if applicable.
    if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
	  // 根据名称装配
      autowireByName(beanName, mbd, bw, newPvs);
    }
    // autowirte_by_type 根据bean对应的class类型设置属性值
    // Add property values based on autowire by type if applicable.
    if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
	  // 根据类型装配 类型就是全限定类名
      autowireByType(beanName, mbd, bw, newPvs);
    }
    pvs = newPvs;
  }

  boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
  boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

  PropertyDescriptor[] filteredPds = null;
  if (hasInstAwareBpps) {
    if (pvs == null) {
      pvs = mbd.getPropertyValues();
    }
	// 各种扩展点
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof InstantiationAwareBeanPostProcessor) {
        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
        PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
        if (pvsToUse == null) {
          if (filteredPds == null) {
            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
          }
          // 各种BeanPostProcessor 会执行到这里 比如 AutowiredAnnotationBeanPostProcessor 对采用 @Autowired、@Value 注解的依赖进行设值
          pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
          if (pvsToUse == null) {
            return;
          }
        }
        pvs = pvsToUse;
      }
    }
  }
  if (needsDepCheck) {
    if (filteredPds == null) {
      filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
    }
    checkDependencies(beanName, mbd, filteredPds, pvs);
  }

  if (pvs != null) {
    // 设置bean实例的属性值
    applyPropertyValues(beanName, mbd, bw, pvs);
  }
}

设置bean实例的属性值(applyPropertyValues)

AbstractAutowireCapableBeanFactory::applyPropertyValues()

/**
    * Apply the given property values, resolving any runtime references
    * to other beans in this bean factory. Must use deep copy, so we
    * don't permanently modify this property.
    * @param beanName the bean name passed for better exception information
    * @param mbd the merged bean definition
    * @param bw the BeanWrapper wrapping the target object
    * @param pvs the new property values
    */
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
    if (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<>(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);
    }
}

解析对应的值(convertForProperty)

/**
  * Convert the given value for the specified target property.
  */
@Nullable
private Object convertForProperty(
    @Nullable Object value, String propertyName, BeanWrapper bw, TypeConverter converter) {

  if (converter instanceof BeanWrapperImpl) {
    // 这里
    return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName);
  }
  else {
    PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
    MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
    return converter.convertIfNecessary(value, pd.getPropertyType(), methodParam);
  }
}

BeanWrapperImpl::convertForProperty

public Object convertForProperty(@Nullable Object value, String propertyName) throws TypeMismatchException {
  CachedIntrospectionResults cachedIntrospectionResults = getCachedIntrospectionResults();
  PropertyDescriptor pd = cachedIntrospectionResults.getPropertyDescriptor(propertyName);
  if (pd == null) {
    throw new InvalidPropertyException(getRootClass(), getNestedPath() + propertyName,
        "No property '" + propertyName + "' found");
  }
  TypeDescriptor td = cachedIntrospectionResults.getTypeDescriptor(pd);
  if (td == null) {
    td = cachedIntrospectionResults.addTypeDescriptor(pd, new TypeDescriptor(property(pd)));
  }
  return convertForProperty(propertyName, null, value, td);
}

AbstractNestablePropertyAccessor::convertForProperty

@Nullable
protected Object convertForProperty(
    String propertyName, @Nullable Object oldValue, @Nullable Object newValue, TypeDescriptor td)
    throws TypeMismatchException {

  return convertIfNecessary(propertyName, oldValue, newValue, td.getType(), td);
}

源码位置: org.springframework.beans.AbstractNestablePropertyAccessor::convertIfNecessary

@Nullable
private Object convertIfNecessary(@Nullable String propertyName, @Nullable Object oldValue,
        @Nullable Object newValue, @Nullable Class<?> requiredType, @Nullable TypeDescriptor td)
        throws TypeMismatchException {

    Assert.state(this.typeConverterDelegate != null, "No TypeConverterDelegate");
    try {
        return this.typeConverterDelegate.convertIfNecessary(propertyName, oldValue, newValue, requiredType, td);
    }
    catch (ConverterNotFoundException | IllegalStateException ex) {
        PropertyChangeEvent pce =
                new PropertyChangeEvent(getRootInstance(), this.nestedPath + propertyName, oldValue, newValue);
        throw new ConversionNotSupportedException(pce, requiredType, ex);
    }
    catch (ConversionException | IllegalArgumentException ex) {
        PropertyChangeEvent pce =
                new PropertyChangeEvent(getRootInstance(), this.nestedPath + propertyName, oldValue, newValue);
        throw new TypeMismatchException(pce, requiredType, ex);
    }
}

源码位置: BeanDefinitionValueResolver::resolveValueIfNecessary()

/**
    * Given a PropertyValue, return a value, resolving any references to other
    * beans in the factory if necessary. The value could be:
    * <li>A BeanDefinition, which leads to the creation of a corresponding
    * new bean instance. Singleton flags and names of such "inner beans"
    * are always ignored: Inner beans are anonymous prototypes.
    * <li>A RuntimeBeanReference, which must be resolved.
    * <li>A ManagedList. This is a special collection that may contain
    * RuntimeBeanReferences or Collections that will need to be resolved.
    * <li>A ManagedSet. May also contain RuntimeBeanReferences or
    * Collections that will need to be resolved.
    * <li>A ManagedMap. In this case the value may be a RuntimeBeanReference
    * or Collection that will need to be resolved.
    * <li>An ordinary object or {@code null}, in which case it's left alone.
    * @param argName the name of the argument that the value is defined for
    * @param value the value object to resolve
    * @return the resolved object
    */
@Nullable
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
    // We must check each value to see whether it requires a runtime reference
    // to another bean to be resolved.
    if (value instanceof RuntimeBeanReference) {
        RuntimeBeanReference ref = (RuntimeBeanReference) value;
        return resolveReference(argName, ref);
    }
    else if (value instanceof RuntimeBeanNameReference) {
        String refName = ((RuntimeBeanNameReference) value).getBeanName();
        refName = String.valueOf(doEvaluate(refName));
        if (!this.beanFactory.containsBean(refName)) {
            throw new BeanDefinitionStoreException(
                    "Invalid bean name '" + refName + "' in bean reference for " + argName);
        }
        return refName;
    }
    else if (value instanceof BeanDefinitionHolder) {
        // Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases.
        BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
        return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
    }
    else if (value instanceof BeanDefinition) {
        // Resolve plain BeanDefinition, without contained name: use dummy name.
        BeanDefinition bd = (BeanDefinition) value;
        String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
                ObjectUtils.getIdentityHexString(bd);
        return resolveInnerBean(argName, innerBeanName, bd);
    }
    else if (value instanceof ManagedArray) {
        // May need to resolve contained runtime references.
        ManagedArray array = (ManagedArray) value;
        Class<?> elementType = array.resolvedElementType;
        if (elementType == null) {
            String elementTypeName = array.getElementTypeName();
            if (StringUtils.hasText(elementTypeName)) {
                try {
                    elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader());
                    array.resolvedElementType = elementType;
                }
                catch (Throwable ex) {
                    // Improve the message by showing the context.
                    throw new BeanCreationException(
                            this.beanDefinition.getResourceDescription(), this.beanName,
                            "Error resolving array type for " + argName, ex);
                }
            }
            else {
                elementType = Object.class;
            }
        }
        return resolveManagedArray(argName, (List<?>) value, elementType);
    }
    else if (value instanceof ManagedList) {
        // May need to resolve contained runtime references.
        return resolveManagedList(argName, (List<?>) value);
    }
    else if (value instanceof ManagedSet) {
        // May need to resolve contained runtime references.
        return resolveManagedSet(argName, (Set<?>) value);
    }
    else if (value instanceof ManagedMap) {
        // May need to resolve contained runtime references.
        return resolveManagedMap(argName, (Map<?, ?>) value);
    }
    else if (value instanceof ManagedProperties) {
        Properties original = (Properties) value;
        Properties copy = new Properties();
        original.forEach((propKey, propValue) -> {
            if (propKey instanceof TypedStringValue) {
                propKey = evaluate((TypedStringValue) propKey);
            }
            if (propValue instanceof TypedStringValue) {
                propValue = evaluate((TypedStringValue) propValue);
            }
            if (propKey == null || propValue == null) {
                throw new BeanCreationException(
                        this.beanDefinition.getResourceDescription(), this.beanName,
                        "Error converting Properties key/value pair for " + argName + ": resolved to null");
            }
            copy.put(propKey, propValue);
        });
        return copy;
    }
    else if (value instanceof TypedStringValue) {
        // Convert value to target type here.
        TypedStringValue typedStringValue = (TypedStringValue) value;
        Object valueObject = evaluate(typedStringValue);
        try {
            Class<?> resolvedTargetType = resolveTargetType(typedStringValue);
            if (resolvedTargetType != null) {
                return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);
            }
            else {
                return valueObject;
            }
        }
        catch (Throwable ex) {
            // Improve the message by showing the context.
            throw new BeanCreationException(
                    this.beanDefinition.getResourceDescription(), this.beanName,
                    "Error converting typed String value for " + argName, ex);
        }
    }
    else if (value instanceof NullBean) {
        return null;
    }
    else {
        return evaluate(value);
    }
}

参考资料

[1] Spring Bean 的装配方式
[2] 装配 Spring Bean 详解
[3] Spring自动装配Bean详解