spring系列15:自动装配

前言

上篇简述了 Spring 如何实例化 Bean,在实例化 Bean 之后还能干嘛,当然是属性注入,这篇分析一下 Spring 如何对属性自动装配。

代码

A.java

package com.playwin.bean;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class A {

   @Autowired
   private B b;

   @Value("Playwi0")
   private String name;


}

B.java

package com.playwin.bean;

import org.springframework.stereotype.Component;

@Component
public class B {


}

doCreateBean

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      throws BeanCreationException {

   // Instantiate the bean.
   BeanWrapper instanceWrapper = null;

   if (mbd.isSingleton()) {
      instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
   }

   if (instanceWrapper == null) {
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
   final Object bean = instanceWrapper.getWrappedInstance();

   // 删除代码
   ....

   Object exposedObject = bean;
    try {

        populateBean(beanName, mbd, instanceWrapper);

        // 删除代码
        ....
    }

   // 删除代码
   ....

   return exposedObject;
}

上篇说过,instanceWrapper = createBeanInstance(beanName, mbd, args);之后,会返回一个实例化对象,但这个对象并不是一个完整的 BeanSpring 在这之后调用 populateBean 方法完成属性注入。

populateBean

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {

    // 删除代码
    ....

   // 配置文件
   PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

   // byName,byType 注入模型
   int resolvedAutowireMode = mbd.getResolvedAutowireMode();
   if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
      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 (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);

             // 删除代码
             ....

            pvs = pvsToUse;
         }
      }
   }

    // 删除代码
    ....
}

在这里会判断注入模型,是 byName 还是 byType,很明显前面是使用注解配置,不存在 byName 还是 byType 注入模型,也就是说 @Autowired 注解和 byName, byType 没啥关系,也并不是某些博客说的那样,@Autowired 注解是根据byName 或 byType 注入。

继续走到下面逻辑,调用 Bean 后置处理器的 postProcessProperties 方法。那调用的是哪个后置处理器;一看便知。

AutowiredAnnotationBeanPostProcessor 很明显,这个后置处理器的名字已经暴露它是处理 @Autowired 注解。究竟是不是看看才知道。

postProcessProperties

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {

   // 找出所有需要自动装配的属性
   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;
}

findAutowiringMetadata 这个方法已经很明,查找 @Autowired 注解数据,放到缓存,调用了metadata.inject(bean, beanName, pvs);

inject

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {

   // 所有自动装配属性
   Collection<InjectedElement> checkedElements = this.checkedElements;
   // 迭代器
   Collection<InjectedElement> elementsToIterate =
         (checkedElements != null ? checkedElements : this.injectedElements);

   if (!elementsToIterate.isEmpty()) {
      // 遍历装配
      for (InjectedElement element : elementsToIterate) {
         if (logger.isTraceEnabled()) {
            logger.trace("Processing injected element of bean '" + beanName + "': " + element);
         }
         element.inject(target, beanName, pvs);
      }
   }
}

拿到所有需要注入属性后,使用迭代器遍历,

进入了element.inject(target, beanName, pvs);

inject(AutowiredFieldElement)

这里面分为注解添加到了属性上面,和方法上面两种逻辑。先看属性

@Override
   protected void inject(Object bean, @Nullable String beanName, @Nullable 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<>(1);
         Assert.state(beanFactory != null, "No BeanFactory available");

         // 获取类型转换器
         TypeConverter typeConverter = beanFactory.getTypeConverter();
         try {
            // 得到自动装配属性的值
            value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
         }
         catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
         }

         // 如果这个自动装配属性也是 Spring 的 Bean,把它加入依赖缓存
         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) &&
                           beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
                        this.cachedFieldValue = new ShortcutDependencyDescriptor(
                              desc, autowiredBeanName, field.getType());
                     }
                  }
               }
               else {
                  this.cachedFieldValue = null;
               }
               this.cached = true;
            }
         }
      }
      // 属性 set 注入
      if (value != null) {
         ReflectionUtils.makeAccessible(field);
         field.set(bean, value);
      }
   }
}

value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);这里会得到属性的值,先不管怎么得到,最后你会看到,属性注入仅仅是调用field.set(bean, value);这么简单代码来完成。

resolveDependency

@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
      @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {


    // 删除代码
    ....

   if (Optional.class == descriptor.getDependencyType()) {
       // 删除代码
       ....
   }
   else {
      Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
            descriptor, requestingBeanName);

      if (result == null) {
         result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
      }
      return result;
   }
}

调用 doResolveDependency 方法

doResolveDependency

@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
      @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

   // 注入节点
   InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);

   try {
      Object shortcut = descriptor.resolveShortcut(this);
      if (shortcut != null) {
         return shortcut;
      }
      // 拿到需要注入属性类型
      Class<?> type = descriptor.getDependencyType();
      // 如果有 @value 注解的值,找出 @value 注解的值
      Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
      if (value != null) {
         // 如果值 @value 注解的值是 String 类型
         // 如果是表达式,这里会执行表达式,value 变量会变成保存表达式结果值
         // 如果不是表达式,会根据属性的类型给属性赋值。
         if (value instanceof String) {
            String strVal = resolveEmbeddedValue((String) value);
            BeanDefinition bd = (beanName != null && containsBean(beanName) ?
                  getMergedBeanDefinition(beanName) : null);
            value = evaluateBeanDefinitionString(strVal, bd);
         }
         TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
         try {
            return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
         }
         catch (UnsupportedOperationException ex) {
            // A custom TypeConverter which does not support TypeDescriptor resolution...
            return (descriptor.getField() != null ?
                  converter.convertIfNecessary(value, type, descriptor.getField()) :
                  converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
         }
      }
      // 属性可以储存多个,集合或数组
      Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
      if (multipleBeans != null) {
         return multipleBeans;
      }

      // 如果前面两种都不是,那么只剩下 @Autowired 注解
      // 根据属性类型找出所有候选 Bean 的 Map 集合
      Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
      if (matchingBeans.isEmpty()) {
         if (isRequired(descriptor)) {
            raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
         }
         return null;
      }

      // 对应的上面找出 Map 集合的 key,value
      String autowiredBeanName;
      Object instanceCandidate;

      // 如果有多个,需要在此筛选
      if (matchingBeans.size() > 1) {
         // 在上面根据属性类型找出的 Map 集合里,再根据属性名字从里面找一遍。
         // 这里也会解析 @primary 注解
         autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);

         if (autowiredBeanName == null) {
            // 没找到,除非类型是集合,可以为空,或者设置 required 值,否则报错
            if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
               return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
            }
            else {

               return null;
            }
         }
         // 找到这个唯一的 Bean,就取出
         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();
      }

      if (autowiredBeanNames != null) {
         autowiredBeanNames.add(autowiredBeanName);
      }
      if (instanceCandidate instanceof Class) {
         // 如果是个类,就实例化,里面是调用 getBean
         instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
      }

      Object result = instanceCandidate;
      // 没有实例化出 Bean???
      // 应该不会进这里
      if (result instanceof NullBean) {
         if (isRequired(descriptor)) {
            raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
         }
         result = null;
      }
      // 再次验证属性类型,是否属于该类型。
      if (!ClassUtils.isAssignableValue(type, result)) {
         throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
      }
      return result;
   }
   finally {
      ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
   }
}

@value 注解会判断是否为表达式,比如配置文件里的属性。终于知道为什么有的文章会说 @Autowired 是 byType 或 byName 注入。这里,Spring 会按自动装配属性的类型找出所有符合的 Bean,如果有多个,再从结果里面按属性名字查找(这样的查找,并没有判断 byType 或 byName),如果没找到,并且没设置@Autowired(required = false)或者属性不是可以存储多个元素类型,则会报错。最后找到的值是类就实例化instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);

public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
      throws BeansException {

   return beanFactory.getBean(beanName);
}

不信咱们测试一下。

一个接口两个实现类。

I.java

package com.playwin.bean;

import org.springframework.stereotype.Component;

@Component
public interface I {

}

IA.java

package com.playwin.bean;

import org.springframework.stereotype.Component;

@Component
public class IA implements I{

}

IB.java

package com.playwin.bean;

import org.springframework.stereotype.Component;

@Component
public class IB implements I{

}

在一个 Bean 设置注入属性。

B.java

package com.playwin.bean;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class B {

   @Autowired
   I a;

}

注意属性类型和名字。按照上面所说,这里会按类型找出两个 Bean,但按名字找不到,报错。

按类型找到两个

按名字没有。

报错。

inject(AutowiredMethodElement)

上面是属性的,@Autowired 注解也是支持添加到方法上的。

@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
   if (checkPropertySkipping(pvs)) {
      return;
   }
   // 获取方法名字
   Method method = (Method) this.member;
   Object[] arguments;
   if (this.cached) {
      // Shortcut for avoiding synchronization...
      arguments = resolveCachedArguments(beanName);
   }
   else {
      // 获取该方法参数个数
      int argumentCount = method.getParameterCount();
      arguments = new Object[argumentCount];
      // 虽说是方法注入,但 Spring 在这里转换为了和属性一样的逻辑
      DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
      Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
      Assert.state(beanFactory != null, "No BeanFactory available");
      TypeConverter typeConverter = beanFactory.getTypeConverter();
      for (int i = 0; i < arguments.length; i++) {
         MethodParameter methodParam = new MethodParameter(method, i);
         DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
         currDesc.setContainingClass(bean.getClass());
         descriptors[i] = currDesc;
         try {
            Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
            if (arg == null && !this.required) {
               arguments = null;
               break;
            }
            arguments[i] = arg;
         }
         catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
         }
      }
      synchronized (this) {
         if (!this.cached) {
            if (arguments != null) {
               DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
               registerDependentBeans(beanName, autowiredBeans);
               if (autowiredBeans.size() == argumentCount) {
                  Iterator<String> it = autowiredBeans.iterator();
                  Class<?>[] paramTypes = method.getParameterTypes();
                  for (int i = 0; i < paramTypes.length; i++) {
                     String autowiredBeanName = it.next();
                     if (beanFactory.containsBean(autowiredBeanName) &&
                           beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
                        cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
                              descriptors[i], autowiredBeanName, paramTypes[i]);
                     }
                  }
               }
               this.cachedMethodArguments = cachedMethodArguments;
            }
            else {
               this.cachedMethodArguments = null;
            }
            this.cached = true;
         }
      }
   }
   // 反射 invoke
   if (arguments != null) {
      try {
         ReflectionUtils.makeAccessible(method);
         method.invoke(bean, arguments);
      }
      catch (InvocationTargetException ex) {
         throw ex.getTargetException();
      }
   }
}

基本一模一样,这是提取出方法中参数,去解析出结果,然后反射执行方法。这里并限制什么方法,也就是说 @Autowired 注解添加到方法上会执行?

package com.playwin.bean;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class A {

   @Value("Playwi0")
   private String name;

   @Autowired
   public void sout(){
      System.out.println("惡搞");
   }
}

可以是可以,但 Spring 并不建议你这样使用,而且这样用没什么卵用。要想执行方法 Spring 也提供了注解方式。

总结

看了这篇,你应该不会单纯的以为 @Autowired 注解是先 byType 再 byName 注入。 @Autowired 和注入模型没有任何关系,严格的说。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值