资讯 小学 初中 高中 语言 会计职称 学历提升 法考 计算机考试 医护考试 建工考试 教育百科
栏目分类:
子分类:
返回
空麓网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
空麓网 > 计算机考试 > 软件开发 > 后端开发 > Java

spring源码-依赖注入@Autowired

Java 更新时间: 发布时间: 计算机考试归档 最新发布

spring源码-依赖注入@Autowired

依赖注入的实现由后置处理器AutowiredAnnotationBeanPostProcessor实现

类图

实现了InstantiationAwareBeanPostProcessor ,MergedBeanDefinitionPostProcessor接口,如果对这两个接口不熟悉的可以阅读上篇文章后置处理器,实现这两个接口就可以介入到Bean的实例化前后和bean的元数据信息解析

依赖注入过程:

第一步、解析注解信息

入口方法:

postProcessMergedBeanDefinition该方法的作用其实比较简单,就是为了缓存下后续需要用到数据,findAutowiringMetadata 这个方法是有缓存的
处理的,所以重复调用的话是直接从缓存获取数据,加快注入的效率。这个方法其实就是去查找被 Autowired、Value 注解的所有属性和方法,当然包
括了目标类的所有父类都会去查找,所以查找的过程其实是个递归的过程。找到所有的成员后,会创建即实例化 
InjectionMetadata 对象并缓存到injectionMetadataCache 。

核心代码:

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) {
   InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
   metadata.checkConfigMembers(beanDefinition);
}


private InjectionMetadata findAutowiringMetadata(String beanName, Class clazz, @Nullable 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);
            }
            //解析所有@Autowired @Value注解的方法和变量
            metadata = buildAutowiringMetadata(clazz);
            //缓存起来
            this.injectionMetadataCache.put(cacheKey, metadata);
         }
      }
   }
   return metadata;
}


private InjectionMetadata buildAutowiringMetadata(final Class clazz) {
   if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
      return InjectionMetadata.EMPTY;
   }

   List elements = new ArrayList<>();
   Class targetClass = clazz;

   do {
      final List currElements = new ArrayList<>();
      //解析带Autowired和@Value的字段
      ReflectionUtils.doWithLocalFields(targetClass, field -> {
         MergedAnnotation ann = findAutowiredAnnotation(field);
         if (ann != null) {
            if (Modifier.isStatic(field.getModifiers())) {
               if (logger.isInfoEnabled()) {
                  logger.info("Autowired annotation is not supported on static fields: " + field);
               }
               return;
            }
            boolean required = determineRequiredStatus(ann);
            currElements.add(new AutowiredFieldElement(field, required));
         }
      });
        //解析带Autowired和@Value的方法
      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;
            }
            if (method.getParameterCount() == 0) {
               if (logger.isInfoEnabled()) {
                  logger.info("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 InjectionMetadata.forElements(elements, clazz);
}

第二步、注入

入口方法

postProcessProperties
该方法在bean实例化后被调用,属性值进行修改,如果postProcessAfterInstantiation方法返回false,该方法可能不会被调用。可以在该方法内对属性值进行修改

核心代码

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    //findAutowiringMetadata方法已经在上一步被执行了一次了,并且将注解的元信息已经放到了缓存里,所以这里就直接从缓存中拿到了。 
    //拿到注解元数据后,就开始执行inject方法了。
   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方法进行注入

 public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
   Collection checkedElements = this.checkedElements;
   Collection 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);
      }
   }
}

核心在DefaultListableBeanFactory#doResolveDependency

// 此处autowiredBeanNames是在inject的一个空的Set
// autowired表示最终可以注入进去的bean名称们(因为可能是会有多个符合条件的)
	public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
...
		@Nullable
		public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
										  @Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

// 记录注入点,其实使用的ThreadLocal~
			InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
			try {
// 只有ShortcutDependencyDescriptor实现了resolveShortcut方法,其实就是根据
// 实现也就一句话:beanFactory.getBean(this.shortcut, this.requiredType)
// ShortcutDependencyDescriptor实在inject完成后创建的,就是有缓存的效果~~~
				Object shortcut = descriptor.resolveShortcut(this);
				if (shortcut != null) {
					return shortcut;
				}

// interface com.fsx.dependency.AInterface
				Class type = descriptor.getDependencyType();

// 拿到@Value注解的value值(是个字符串)  若没有标注@Value  显然就不用那啥了
// 从此处其实也可以看出,@Value注解的优先级对于找到bean来说还是蛮高的
				Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);


// ============ 这部分主要是解析@Value注解
// 解析它的占位符,解析它的SpEL表达式
// 相关处理类曹靠BeanExpressionResolver和StandardBeanExpressionResolver  StandardEvaluationContext等
// 因为关于@Value的文章里详细解过,此处一笔带过~~~
				if (value != null) {
					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()));
					}
				}
// ============


// 此处处理的是多值注入的情况,比如注入Stream、Map、Array、Collection等等  Spring都是支持的
// 需要稍微注意一点,Stream这种类型的注入在Spring4以上才得到支持的
				Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
				if (multipleBeans != null) {
					return multipleBeans;
				}

// 显然绝大部分情况下,都会走到这里(因为大部分我们都是单值注入~)
// findAutowireCandidates可以说又是整个依赖注入的灵魂之一~~~~ 它的查找步骤简述如下:
//1、BeanFactoryUtils.beanNamesForTypeIncludingAncestors() 找到这种类型的所有的beanNames(candidateNames)(可能有多个哟,但大多数情况下只有一个)
//2、处理resolvableDependencies比如ApplicationContext的依赖,让他们也能够正常注入进去(他们可不作为bean存在容器里~)
//3、遍历candidateNames:检查它是否可以被依赖、容器内是否存在bean定义(或者Singleton) 若符合,getBean()出来放在map里
//4、若返回的Map不为Empty()了,直接return  表示找到了(当然还可能是多个~~)
// 若返回的还是Empty,那就继续检查requiredType是否为Map、Collection等类型,从它里面去找。。。(这种注入case使用太少,此处暂略~)
				Map matchingBeans = findAutowireCandidates(beanName, type, descriptor);
// 所以matchingBeans证明没有找到匹配的,但requied=true,所以此处就抛出异常了~
				if (matchingBeans.isEmpty()) {
					if (isRequired(descriptor)) {
						raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
					}
					return null;
				}

				String autowiredBeanName;
				Object instanceCandidate;

// 若有多个匹配
// 需要注意的是:@Qualifier注解在上面就已经生效了~~~~因为AutowireCandidateResolver.isAutowireCandidate是在上面生效的
				if (matchingBeans.size() > 1) {
// 由它进行判别  从弱水三千中  取出一瓢
// 1、是否标注有@Primary  有这种bean就直接返回(@Primary只允许标注在一个同类型Bean上)
// 2、看是否有标注有`javax.annotation.Priority`这个注解的
// 3、根据字段field名,去和beanName匹配  匹配上了也行(这就是为何我们有时候不用@Qulifier也没事的原因之一)
// 此处注意:descriptor.getDependencyName()这个属性表示字段名,靠的是`DefaultParameterNameDiscoverer`去把字段名取出来的~
					autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
					if (autowiredBeanName == null) {
						if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {

// 此处抛出异常:NoUniqueBeanDefinitionException
							return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
						} else {
							return null;
						}
					}
					instanceCandidate = matchingBeans.get(autowiredBeanName);
				} else { // 只有一个匹配就啥都说了  干就完了
// We have exactly one match.
					Map.Entry 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;
				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);
			}
		}
...
	} 

findAutowireCandidates源码分析

protected Map findAutowireCandidates(
      @Nullable String beanName, Class requiredType, DependencyDescriptor descriptor) {

   // 从BeanFactory中找出和requiredType所匹配的beanName,仅仅是beanName,这些bean不一定经过了实例化,只有到最终确定某个Bean了,如果这个Bean还没有实例化才会真正进行实例化
   String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
         this, requiredType, true, descriptor.isEager());
   Map result = CollectionUtils.newLinkedHashMap(candidateNames.length);

   // 根据类型从resolvableDependencies中匹配Bean,resolvableDependencies中存放的是类型:Bean对象,比如BeanFactory.class:BeanFactory对象,在Spring启动时设置。
   for (Map.Entry, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
      // 得到当前Bean的类型
      Class autowiringType = classObjectEntry.getKey();
      if (autowiringType.isAssignableFrom(requiredType)) {
         // 获取缓存中的值
         Object autowiringValue = classObjectEntry.getValue();
         // 这里会生成一个Bean的名字,放到缓存中的是没有Bean的名字的
         autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);

         // 类型匹配,将当前值添加进去
         if (requiredType.isInstance(autowiringValue)) {
            result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
            break;
         }
      }
   }

   // 这里理解就是注入同一个Bean的时候,先考虑同类型的其他Bean
   for (String candidate : candidateNames) {
      // 如果不是自己,则判断该candidate到底能不能用来进行自动注入(@Bean(autowireCandidate = true))默认为true
      if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
         // 不是自己,并且可以注入的时候,调用这个代码:添加候选者
         addCandidateEntry(result, candidate, descriptor, requiredType);
      }
   }

   // 为空要么是真的没有匹配的,要么是匹配的自己
   if (result.isEmpty()) {
      // 需要匹配的类型是不是Map、数组之类的
      boolean multiple = indicatesMultipleBeans(requiredType);
      // Consider fallback matches if the first pass failed to find anything...
      // 如果第一遍找不到任何东西,请考虑回退匹配。
      DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
      // 遍历每个候选者
      for (String candidate : candidateNames) {
         // 不是自己并且可以被注入并且(不是Map、数组之类的或者@Qualifier指定了BeanName的)
         if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
               (!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
            // 添加真正的候选者
            addCandidateEntry(result, candidate, descriptor, requiredType);
         }
      }

      // 匹配的是自己,把自己添加到result中。
      if (result.isEmpty() && !multiple) {
         // 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;
}

转载请注明:文章转载自 http://www.konglu.com/
免责声明:

我们致力于保护作者版权,注重分享,被刊用文章【spring源码-依赖注入@Autowired】因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理,本文部分文字与图片资源来自于网络,转载此文是出于传递更多信息之目的,若有来源标注错误或侵犯了您的合法权益,请立即通知我们,情况属实,我们会第一时间予以删除,并同时向您表示歉意,谢谢!

我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2023 成都空麓科技有限公司

ICP备案号:蜀ICP备2023000828号-2