spring源码解析(二) @Autowired自动注入过程

1.依赖注入到底有几种?两种、四种、五种?

两种:

手动:set(byType、byName)、构造器

自动:xml中:set、构造器 autowired注解中:set、属性、构造器

重点不在于到底有几种,而在于是否真的理解了依赖注入。

2.@Autowired注解方式自动注入源码过程

具体分析属性填充populateBean方法:只看关键部分,注入的部分

  // 是否在BeanDefinition中设置了属性值
   PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

   int resolvedAutowireMode = mbd.getResolvedAutowireMode();
   if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
      // by_name是根据根据属性名字找bean
      // by_type是根据属性所对应的set方法的参数类型找bean
      // 找到bean之后都要调用set方法进行注入

      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;
      // 注意,执行完这里的代码之后,这是把属性以及找到的值存在了pvs里面,并没有完成反射赋值
   }

   // 执行完了Spring的自动注入之后,就开始解析@Autowired,这里叫做实例化回调
   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;
            // 调用BeanPostProcessor分别解析@Autowired、@Resource、@Value,得到属性值
            PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
               if (filteredPds == null) {
                  filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
               }
               pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
               if (pvsToUse == null) {
                  return;
               }
            }
            pvs = pvsToUse;
         }
      }
   }
}

xml方式的byName和byType

简单说一下xml的byType和byName

Spring在通过byName的自动填充属性时流程是:

  1. 找到所有set方法所对应的XXX部分的名字
  2. 根据XXX部分的名字去获取bean

Spring在通过byType的自动填充属性时流程是:

  1. 找到所有set方法所对应的XXX部分的名字
  2. 根据XXX部分的名字重新再获取得到PropertyDescriptor
  3. 获取到set方法中的唯一参数的类型,并且根据该类型去容器中获取bean
  4. 如果找到多个,会报错

然后进autowireByType方法看一下源码:resolveDependency 是一个核心方法,稍后在@Autowired处分析。beanDefinition方式解析不做过多分析

TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
   converter = bw;
}

Set<String> autowiredBeanNames = new LinkedHashSet<>(4);

// 找到有对应set方法的属性
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()) {
         // set方法中的参数信息
         MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);

         // Do not allow eager init for type matching in case of a prioritized post-processor.
         // 当前Bean是否实现了PriorityOrdered
         boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
         DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);

         // 根据类型找bean,这就是byType
         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);
   }
}

接下来分析@Autowired方式注入,重新回到填充属性方法populateBean中,看这一段BeanPostProcessor的postProcessProperties方法调用。

for (BeanPostProcessor bp : getBeanPostProcessors()) {
   if (bp instanceof InstantiationAwareBeanPostProcessor) {
      InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
      //用于进行@Autowired和@Value、@Resource的注入
      PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
      if (pvsToUse == null) {
         if (filteredPds == null) {
            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
         }
         pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
         if (pvsToUse == null) {
            return;
         }
      }
      pvs = pvsToUse;
   }
}

直至循环到AutowiredAnnotationBeanPostProcessor的postProcessProperties方法,

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()->buildAutowiringMetadata()方法中,看这一段源码:

// 遍历属性,看是否有@Autowired,@Value,@Inject注解
ReflectionUtils.doWithLocalFields(targetClass, field -> {
    // 如果存在@Autowired,@Value,@Inject注解其中一个
   MergedAnnotation<?> ann = findAutowiredAnnotation(field);
   if (ann != null) {
       // 如果字段是static的,则直接进行返回,不进行注入
      if (Modifier.isStatic(field.getModifiers())) {
         if (logger.isInfoEnabled()) {
            logger.info("Autowired annotation is not supported on static fields: " + field);
         }
         return;
      }
      //required属性注入
      boolean required = determineRequiredStatus(ann);
      // 生成一个注入点AutowiredFieldElement,这个在属性填充前(MergedBeanDefinitionPostProcessor中)
      //,此时只是告诉spring要注入这些,还没有真正注入。
      //真正注入还是在属性填充内完成
      currElements.add(new AutowiredFieldElement(field, required));
   }
});

@Autowired为什么不支持静态的 ?

静态变量、类变量不是对象的属性,而是一个类的属性,所以静态方法是属于类(class)的,普通方法才是属于实体对象(也就是New出来的对象)的,spring注入是在容器中实例化对象,所以不能使用静态方法。而使用静态变量、类变量扩大了静态方法的使用范围。静态方法在spring是不推荐使用的,依赖注入的主要目的,是让容器去产生一个对象的实例,然后在整个生命周期中使用他们,同时也让testing工作更加容易。一旦你使用静态方法,就不再需要去产生这个类的实例,这会让testing变得更加困难,同时你也不能为一个给定的类,依靠注入方式去产生多个具有不同的依赖环境的实例,这种static field是隐含共享的,并且是一种global全局状态,spring同样不推荐这样去做。

然后进行进入findAutowiredAnnotation方法,该方法是为了获取是否有这些注解

private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
   // 查看当前字段上是否存在@Autowired,@Value,@Inject注解,存在其中一个则返回,表示可以注入
   MergedAnnotations annotations = MergedAnnotations.from(ao);
   // autowiredAnnotationTypes是一个LinkedHashSet,所以会按顺序去判断当前字段中是否有Autowired注解,如果有则返回
   // 如果没有Autowired注解,那么则判断是否有Value注解,再判断是否有Inject注解
   for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
      MergedAnnotation<?> annotation = annotations.get(type);
      if (annotation.isPresent()) {
         return annotation;
      }
   }
   return null;
}

为什么会只查看@Autowired,@Value,@Inject注解?

因为autowiredAnnotationTypes里只添加了这三个,为什么会先判断@Autowired,是因为是LinkedHashSet,按添加顺序去判断,看一下源码添加逻辑

public AutowiredAnnotationBeanPostProcessor() {
   this.autowiredAnnotationTypes.add(Autowired.class);
   this.autowiredAnnotationTypes.add(Value.class);
   try {
       //如果有这个类就添加,没有则跳过
      this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
            ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
      logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
   }
   catch (ClassNotFoundException ex) {
      // JSR-330 API not available - simply skip.
   }
}

我们返回到buildAutowiringMetadata()方法中:刚才是遍历了所有属性,接下来是遍历所有方法,本质上还是通过方法获取到了属性。

// 遍历方法,看是否有@Autowired,@Value,@Inject注解
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
   Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
   if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
      return;
   }
   MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
   if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
      // 静态方法不能用来注入属性
      if (Modifier.isStatic(method.getModifiers())) {
         if (logger.isInfoEnabled()) {
            logger.info("Autowired annotation is not supported on static methods: " + method);
         }
         return;
      }
      // 方法参数值为0,不能用来注入属性
      if (method.getParameterCount() == 0) {
         if (logger.isInfoEnabled()) {
            logger.info("Autowired annotation should only be used on methods with parameters: " +
                  method);
         }
      }
      // 看是否有@required注解
      boolean required = determineRequiredStatus(ann);
      // 根据方法找出对应的属性
      PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
      currElements.add(new AutowiredMethodElement(method, required, pd));
   }
});

findAutowiringMetadata()方法内的内容执行完毕,获取到注入点的元信息metadata,然后接下来将注入点注入进去。

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    //获取到注解的元信息metadata
   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;
}

进入到inject方法中,这里是循环将InjectedElement进行注入。

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

再向里面走,进入inject方法,这时使用的是子类重写的inject方法,而不是自己的inject方法。

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
   Field field = (Field) this.member;
   Object value;
   if (this.cached) {
      // 当前注入点已经注入过了,有缓存了,则利用cachedFieldValue去找对应的bean
      value = resolvedCachedArgument(beanName, this.cachedFieldValue);
   }
   else {
      //  Spring在真正查找属性对应的对象之前, 会先将该属性的描述封装成一个DependencyDescriptor(依赖描述)对象,
      // 里面保存了Filed、是否强制需要即required, 以及属性所在的类(即Field所在的类Class对象)
      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 {
         // 根据field去寻找合适的bean
         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;
               // 注册当前bean依赖了哪些其他的bean的name
               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;
         }
      }
   }
   // 反射设值,直到这里才真真正正的将注入点要注入的内容注入进来,完成赋值
   if (value != null) {
      ReflectionUtils.makeAccessible(field);
      field.set(bean, value);
   }
}

如何根据field去寻找合适的bean,深入到的方法resolveDependency()里。该方法里前半部分主要为了判断依赖描述的类型,直接看后半段。

如Optional方法用get得到。ObjectFactory可用于注入每次都去getObject,如原型模式可以是不同对象。

else {
   // 在使用@Autowired注解时,也可以使用@Lazy注解,到时候注入的会是一个代理对象
   Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
         descriptor, requestingBeanName);

   if (result == null) {
      // 通过解析descriptor找到bean对象
      result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
   }
   return result;
}

具体解析还是在doResolveDependency()方法中,进去查看,这个方法内容比较多,我们来慢慢分析

一开始进行了缓存判断和@Value注解的解析

//依赖描述信息的缓存判断
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
   return shortcut;
}
//获取依赖描述的类
Class<?> type = descriptor.getDependencyType();
//获取该注入对象上的@Value注解,这也可以知道@Autowired和@Value是可以同时使用的
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);

获取到@Value后进行判断是否存在,先分析存在的情况

if (value != null) {
   if (value instanceof String) {
      // 先进行占位符的填充,解析"$"符号,如@Value("${aa}")
      String strVal = resolveEmbeddedValue((String) value);

      BeanDefinition bd = (beanName != null && containsBean(beanName) ?
            getMergedBeanDefinition(beanName) : null);

      // 解析Spring EL表达式,解析"#"符号(可以进行运算,可以写某个bean的名字)
      value = evaluateBeanDefinitionString(strVal, bd);
   }

再来分析不存在的情况,先判断了依赖描述的类型

// 要注入的依赖的类型是不是一个Map、Array、Collection,不是的话就继续走。 
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
   return multipleBeans;
}

当不是以上三种类型的情况下,到下面调用了这个方法findAutowireCandidates(寻找注入的候选者),在resolveMultipleBeans方法中其实也是这个核心方法。

返回的map中的value是对象,可能是bean对象,也可能是class对象,因为该方法不负责实例化。

Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);

接下来分析一下findAutowireCandidates这个方法。

//去当前beanfactory以及祖先beanfactory中找类型为requiredType的bean的名字,将找到的name作为候选者记录下来
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
      this, requiredType, true, descriptor.isEager());
Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
//把resolvableDependencies中保存的对象作为当前属性的一个候选者? ------这段代码不是太理解
for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
   Class<?> autowiringType = classObjectEntry.getKey();
   if (autowiringType.isAssignableFrom(requiredType)) {
      Object autowiringValue = classObjectEntry.getValue();
      autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
      if (requiredType.isInstance(autowiringValue)) {
         result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
         break;
      }
   }
}
//对候选者进行过滤,
//两个判断,第一个判断是否是自己的引用
//第二个判断为是否能被注入,里面包含了对@Qualifier注解的判断,如果有@Qualifier,则确认@Qualifier的name与descriptor的是否一致
//如:@Autowired
//@Qualifier("order")
//public Order order22; 
//就会注入一个beanName为order,调用为order22的bean。
//只使用@Autowired的话会寻找到type为order的bean,如果只有一个bean,那么正确返回,如果有多个则抛出异常
for (String candidate : candidateNames) {
   if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
      addCandidateEntry(result, candidate, descriptor, requiredType);
   }
}
//如果已经有候选者则直接返回,没有则进行下面流程
if (result.isEmpty()) {
   boolean multiple = indicatesMultipleBeans(requiredType);
   //如果第一次传递找不到任何内容,请考虑回退匹配。。。
   DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
   for (String candidate : candidateNames) {
      if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
            (!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
         addCandidateEntry(result, candidate, descriptor, requiredType);
      }
   }
   if (result.isEmpty() && !multiple) {
      // 如果还是没有,则放宽要求,允许自己注入自己,但不是同一个bean
      for (String candidate : candidateNames) {
         if (isSelfReference(beanName, candidate) &&
               (!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
               isAutowireCandidate(candidate, fallbackDescriptor)) {
            addCandidateEntry(result, candidate, descriptor, requiredType);
         }
      }
   }
}
return result;

然后返回了候选者列表,如果不存在就去判断required是否为true,为true则报错,为false直接返回null

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

接着开始判断候选者的个数,如果只有一个,则返回,多个进行进一步的处理。

先来分析简单的,一个的情况,会执行下面代码

else {
   // 只有一个
   Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
   autowiredBeanName = entry.getKey();
   instanceCandidate = entry.getValue();
}

接下来就是将获得的autowiredBeanName和instanceCandidate进行一些判断,不一一列举了。找个典型的:

//来判断获取的这个对象是bean还是class对象,如果是class对象则调用getBean方法
if (instanceCandidate instanceof Class) {
   instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}

然后回到候选者数量判断那里,如果是多个的情况:会调用determineAutowireCandidate方法

if (matchingBeans.size() > 1) {
   autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);

进入determineAutowireCandidate方法,里面进行了@Primary和@Priority注解的判断,可以得知顺序为先判断@Primary,再判断@Priority

String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
if (primaryCandidate != null) {
   return primaryCandidate;
}
String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
if (priorityCandidate != null) {
   return priorityCandidate;
}

至此,resolveDependency方法的核心内容分析完毕,整个依赖注入的过程也分析完了,稍微总结一下。

@Autowired注入过程总结

依赖注入的流程:在bean实例化后进行属性填充,忽略xml配置的方式,只说@Autowired的过程。

1.通过InstantiationAwareBeanPostProcessor#postProcessProperties切入,进行@Autowired和@Value、@Resource的注入点的注入。

2.判断是否存在@Autowired,@Value,@Inject注解是否存在任意一个,存在就保存为注入点,以便之后的注入。

3.将注入点进行注入。

3.1 发现有@Value注解,则进行#和$的表达式的解析,返回相应bean。

3.2 进行注入,发现没有@Value注解,则寻找候选者。

4.寻找到所有符合的候选者,然后进行过滤

4.1如果有@Qualifier注解,则进行判断@Qualifier上的name与bean中的name是否一致,符合的通过筛选

5.筛选结束,进行候选个数判断

5.1.如果只有一个,则返回对应的bean

5.2.如果还有多个,则进一步的筛选

6.进行@Primary和@Priority注解的筛选

6.1.如果有一个@Primary注解,则返回对应的bean,多个报错。

6.2.如果没有@Primary注解,则进行@Priority注解的筛选,数字越小优先级越高,返回优先级最高的bean

7.通过反射就bean的值设置进来,完成注入。

(每次没找到bean,就会判断一下required)

题外话:如果是@Resource方式注入(j2ee的注解),有几种方式(针对同种type有多个的情况):

1.如果不写name,但存在对应的bean,则直接返回。

2.如果不写name,还不存在bean,则报错。

3.如果写了name,但不存在对应的bean,则会执行@Autowired的逻辑。

4.如果写了name,并存在对应的bean,则会直接通过byName去找。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值