手动注入
a)set方式注入
-
b)构造方法注入
-
自动注入
a)XML的autowire自动注入
b) @Autowired注解的自动注入
属性填充部分源码:
- /**
- * 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;
- }
- }
-
- // 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.
- // 实例化之后,属性设置之前
- if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
- for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
- if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
- return;
- }
- }
- }
-
- PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
-
- int resolvedAutowireMode = mbd.getResolvedAutowireMode();
- if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
- // MutablePropertyValues是PropertyValues具体的实现类
- MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
- // Add property values based on autowire by name if applicable.
- if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
- autowireByName(beanName, mbd, bw, newPvs);
- }
- // Add property values based on autowire by type if applicable.
- if (resolvedAutowireMode == 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 (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
- // 这里会调用AutowiredAnnotationBeanPostProcessor的postProcessProperties()方法,会直接给对象中的属性赋值
- // AutowiredAnnotationBeanPostProcessor内部并不会处理pvs,直接返回了
- PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
- if (pvsToUse == null) {
- if (filteredPds == null) {
- filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
- }
- pvsToUse = bp.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);
- }
-
- // 如果当前Bean中的BeanDefinition中设置了PropertyValues,那么最终将是PropertyValues中的值,覆盖@Autowired
- if (pvs != null) {
- applyPropertyValues(beanName, mbd, bw, pvs);
- }
- }
-
- /**
- * Fill in any missing property values with references to
- * other beans in this factory if autowire is set to "byName".
- * @param beanName the name of the bean we're wiring up.
- * Useful for debugging messages; not used functionally.
- * @param mbd bean definition to update through autowiring
- * @param bw the BeanWrapper from which we can obtain information about the bean
- * @param pvs the PropertyValues to register wired objects with
- */
- protected void autowireByName(
- String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
-
- // 当前Bean中能进行自动注入的属性名
- String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
- // 遍历每个属性名,并去获取Bean对象,并设置到pvs中
- for (String propertyName : propertyNames) {
- if (containsBean(propertyName)) {
- Object bean = getBean(propertyName);
- pvs.add(propertyName, bean);
- // 记录一下propertyName对应的Bean被beanName给依赖了
- registerDependentBean(propertyName, beanName);
- if (logger.isTraceEnabled()) {
- logger.trace("Added autowiring by name from bean name '" + beanName +
- "' via property '" + propertyName + "' to bean named '" + propertyName + "'");
- }
- }
- else {
- if (logger.isTraceEnabled()) {
- logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
- "' by name: no matching bean found");
- }
- }
- }
- }
-
- /**
- * Abstract method defining "autowire by type" (bean properties by type) behavior.
- *
This is like PicoContainer default, in which there must be exactly one bean
- * of the property type in the bean factory. This makes bean factories simple to
- * configure for small namespaces, but doesn't work as well as standard Spring
- * behavior for bigger applications.
- * @param beanName the name of the bean to autowire by type
- * @param mbd the merged bean definition to update through autowiring
- * @param bw the BeanWrapper from which we can obtain information about the bean
- * @param pvs the PropertyValues to register wired objects with
- */
- protected void autowireByType(
- String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
-
- TypeConverter converter = getCustomTypeConverter();
- if (converter == null) {
- converter = bw;
- }
-
- Set
autowiredBeanNames = new LinkedHashSet<>(4); -
- // 当前Bean中能进行自动注入的属性名
- String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
- for (String propertyName : propertyNames) {
- try {
- PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
- // Don't try autowiring by type for type Object: never makes sense,
- // even if it technically is a unsatisfied, non-simple property.
- if (Object.class != pd.getPropertyType()) {
- MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
- // Do not allow eager init for type matching in case of a prioritized post-processor.
- // eager表示立即初始化,表示在根据类型查找Bean时,允不允许进行Bean的创建,如果当前bean实现了PriorityOrdered,那么则不允许
- // 为什么不允许,因为我自己是PriorityOrdered,是优先级最高的,不能有比我创建得更早的
- boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
- DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
- // 根据类型找到的结果
- Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
- if (autowiredArgument != null) {
- pvs.add(propertyName, autowiredArgument);
- }
- for (String autowiredBeanName : autowiredBeanNames) {
- registerDependentBean(autowiredBeanName, beanName);
- if (logger.isTraceEnabled()) {
- logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
- propertyName + "' to bean named '" + autowiredBeanName + "'");
- }
- }
- autowiredBeanNames.clear();
- }
- }
- catch (BeansException ex) {
- throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
- }
- }
- }
-
- /**
- * Return an array of non-simple bean properties that are unsatisfied.
- * These are probably unsatisfied references to other beans in the
- * factory. Does not include simple properties like primitives or Strings.
- * @param mbd the merged bean definition the bean was created with
- * @param bw the BeanWrapper the bean was created with
- * @return an array of bean property names
- * @see org.springframework.beans.BeanUtils#isSimpleProperty
- */
- protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
- Set
result = new TreeSet<>(); - PropertyValues pvs = mbd.getPropertyValues();
- PropertyDescriptor[] pds = bw.getPropertyDescriptors();
-
- // 什么样的属性能进行自动注入?
- // 1.该属性有对应的set方法
- // 2.没有在ignoredDependencyTypes中
- // 3.如果该属性对应的set方法是实现的某个接口中所定义的,那么接口没有在ignoredDependencyInterfaces中
- // 4.属性类型不是简单类型,比如int、Integer、int[]
- for (PropertyDescriptor pd : pds) {
- if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
- !BeanUtils.isSimpleProperty(pd.getPropertyType())) {
- result.add(pd.getName());
- }
- }
- return StringUtils.toStringArray(result);
- }
- // Bean的自动注入模式包括:byType、byName、constructor、default、no
注意:上面这种写法Spring会自动给所有属性赋值,不需要在属性上添加@Autowired注解,但是需要属性对应的set方法
get方法的定义: 方法参数个数为0个,并且(方法名字以"get"开头或者方法名字以"is"开头并且方法的返回类型为boolean)
set方法的定义:方法参数个数为1个,并且(方法名字以"set"开头并且方法返回类型为void)
在创建Bean的过程-填充属性时,Spring会去解析当前类,把当前类的所有方法都解析出来,解析每个方法得到对应的PropertyDescriptor对象(属性描述器)
- public class PropertyDescriptor extends FeatureDescriptor
- {
- // get方法对应返回值类型,set方法对应唯一参数类型
- private Reference extends Class>> propertyTypeRef;
- // get方法的Method对象的引用
- private final MethodRef readMethodRef = new MethodRef();
- // set方法的Method对象的引用
- private final MethodRef writeMethodRef = new MethodRef();
- private Reference extends Class>> propertyEditorClassRef;
-
- private boolean bound;
- private boolean constrained;
-
- // The base name of the method name which will be prefixed with the
- // read and write method. If name == "foo" then the baseName is "Foo"
- private String baseName;
-
- // set方法的名字
- private String writeMethodName;
- // get方法的名字
- private String readMethodName;
-
- ... ...
- }
Spring通过byName自动填充属性流程:
1、找到所有set方法所对应的XXX部分的名字
(public void setXXX(XXX xxx){ ... ...})
2、根据XXX部分的名字去获取bean
Spring通过byType自动填充属性流程:
1、获取到set方法中的唯一参数的类型,并且根据该类型去容器中获取bean
(public void setXXX(XXX xxx){ ... ...})
2、如果找到多个会报错
Spring通过constructor自动填充属性流程:因为推断构造方法,所以只考虑一个有参构造方法的情况
1、利用构造方法的参数信息从Spring容器中去找bean
2、找到bean之后作为参数传给构造方法,从而实例化得到一个bean对象,并完成属性赋值
(属性赋值的代码得程序员来写,this.XXX = XXX)
构造方法注入相当于byType+byName,普通的byType是根据set方法中的参数类型去找bean,找到多个会报错,而constructor就是通过构造方法中的参数类型去找bean,如果找到多个会根据参数名确定。
no,表示关闭autowire
default,表示默认值,
官方描述:
Essentially, the @Autowired annotation provides the same capabilities as described in Autowiring Collaborators but with more fine‐grained control and wider applicability
翻译:从本质上讲,@Autowired注解提供了与autowire相同的功能,但是拥有更细粒度的控制和更广泛的适用性。
XML中的autowire控制的是整个bean的所有属性,而@Autowired注解是直接写在某个属性、某个set方法、某个构造方法上的。
@Autowired注解,是byType和byName的结合
@Autowired注解可以写在:
1、属性上:先根据属性类型去找Bean,如果找到多个再根据属性名确定一个
2、构造方法上:先根据方法参数类型去找Bean,如果找到多个再根据参数名确定一个
3、set方法上:先根据方法参数类型去找Bean,如果找到多个再根据参数名确定一个
底层用到:属性注入、set方法注入、构造方法注入