Spring 依赖注入源码

文章目录

  • 依赖注入
    • 原始依赖注入方式
    • 注解方式
      • 寻找注入点
      • 注入点进行注入
    • 从BeanFactory中找注入对象
    • 总结

依赖注入

具体代码是在AbstractAutowireCapableBeanFactory类的populateBean()方法,此方法中主要做的事情如下:

  • 实例化之后,调用InstantiationAwareBeanPostProcessor接口的postProcessAfterInstantiation方法
  • Spring早期通过BY_NAME或BY_TYPE两种方式,并利用set方法进行依赖注入
  • 通过InstantiationAwareBeanPostProcessor接口的postProcessProperties()方法进行依赖注入,典型的代表就是@Autowired等注解的处理
  • 将BeanDefinition中的PropertyValues覆盖@Autowired等注解的值



原始依赖注入方式

在线流程图

在这里插入图片描述


首先分析Spring早期的依赖注入

@Bean(autowire = Autowire.BY_NAME)
public UserService userService(){
   return new UserService();
}

接下来就会遍历UserService中所有的set方法进行依赖注入。

对应的Spring源码是

PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// 必须是BY_NAME或BY_TYPE
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
   // MutablePropertyValues是PropertyValues具体的实现类
   MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
   // 这里会根据我们的配置来分别调用不同的方法
   if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
      autowireByName(beanName, mbd, bw, newPvs);
   }
   if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
      autowireByType(beanName, mbd, bw, newPvs);
   }
   pvs = newPvs;
}

接下来看autowireByName()方法,主要过程就是先根据set方法找出所有的属性名,然后在遍历属性名集合,去单例池中找,再赋值给pvs变量

protected void autowireByName(
      String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

   // 当前Bean中能进行自动注入的属性名,是根据setXXX()方法生成是属性名
   String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
   // 遍历每个属性名,并去获取Bean对象,并设置到pvs中
   for (String propertyName : propertyNames) {
      // 要进行依赖注入的属性在当前容器中是否存在
      if (containsBean(propertyName)) {
         // 从容器中取出来,再存入pvs中
         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");
         }
      }
   }
}

autowireByType()方法其实也类似,首先得到属性名集合,再遍历集合,然后得到方法形参的类型,根据resolveDependency()找到bean对象,再存入pvs



注解方式

在线流程图

在这里插入图片描述


我们常用的方式是利用@Autowired等注解的方式实现依赖注入的,在Spring源码AbstractAutowireCapableBeanFactory类的populateBean()方法中对应的实现其实就是利用InstantiationAwareBeanPostProcessor接口的postProcessProperties()方法实现的

for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
   // @Autowired注解 这里会调用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;
}

@Autowired@Value注解是通过AutowiredAnnotationBeanPostProcessor类处理的

@Resource注解是通过CommonAnnotationBeanPostProcessor类处理的


实现看AutowiredAnnotationBeanPostProcessor类的定义,它实现了初始化后置处理器以及BeanDefinition后置处理器两个接口,所以该类就会有下面两个方法

InstantiationAwareBeanPostProcessor接口的postProcessProperties()方法

MergedBeanDefinitionPostProcessor接口的postProcessMergedBeanDefinition()方法

public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor,
      MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
          ...
}

根据我们对Bean生命周期的了解可以知道,postProcessMergedBeanDefinition()方法先执行,postProcessProperties()方法后执行



寻找注入点

我们可以先想一想如果要自己实现依赖注入应该要怎么做?首先就是找出类里面所有加了@Autowired注解的属性和Set方法,这个也称为注入点,然后在为这些注入点赋值。接下来看具体的实现,首先的BeanDefinition的后置处理器方法

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
   // 根据类的class对象找到所有的注入点
   InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
   metadata.checkConfigMembers(beanDefinition);
}

先看findAutowiringMetadata()方法逻辑

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
   // cacheKey其实就beanName
   String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
   // 该类的所有注入点会缓存到injectionMetadataCache中
   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);
            }
            // 解析注入点并缓存
            metadata = buildAutowiringMetadata(clazz);
            this.injectionMetadataCache.put(cacheKey, metadata);
         }
      }
   }
   return metadata;
}

核心方法就是buildAutowiringMetadata()根据class找到所有的注入点

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
   // 如果一个Bean的类型是java.*包下的类,比如String,那么则根本不需要为该类进行依赖注入
   if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
      return InjectionMetadata.EMPTY;
   }

   List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
   Class<?> targetClass = clazz;

   do {
      final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

      // 遍历targetClass中的所有Field,每个field都去执行第二个参数的lambda表达式
      ReflectionUtils.doWithLocalFields(targetClass, field -> {
         // field上是否存在@Autowired、@Value、@Inject中的其中一个
         MergedAnnotation<?> ann = findAutowiredAnnotation(field);
         if (ann != null) {
            // static filed不是注入点,不会进行自动注入
            if (Modifier.isStatic(field.getModifiers())) {
               if (logger.isInfoEnabled()) {
                  logger.info("Autowired annotation is not supported on static fields: " + field);
               }
               return;
            }

            // 解析@Autowired注解中的required属性的值,判断这个字段是否是必须要进行注入
            boolean required = determineRequiredStatus(ann);
            // 再构造一个 AutowiredFieldElement 对象作为注入点对象存入集合中
            currElements.add(new AutowiredFieldElement(field, required));
         }
      });

      // 遍历targetClass中的所有Method,每个Method对象都去执行后面的lambda表达式
      ReflectionUtils.doWithLocalMethods(targetClass, method -> {

         // 判断当前Method是否是桥接方法,如果是找到原方法
         Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
         if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
            return;
         }
         // method上是否存在@Autowired、@Value、@Inject中的其中一个
         MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
         if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
            // static method不是注入点,不会进行自动注入
            if (Modifier.isStatic(method.getModifiers())) {
               if (logger.isInfoEnabled()) {
                  logger.info("Autowired annotation is not supported on static methods: " + method);
               }
               return;
            }
            // set方法最好有入参
            if (method.getParameterCount() == 0) {
               if (logger.isInfoEnabled()) {
                  logger.info("Autowired annotation should only be used on methods with parameters: " +
                        method);
               }
            }
            // 解析@Autowired注解中的required属性的值
            boolean required = determineRequiredStatus(ann);
            PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
            // 再构造一个 AutowiredMethodElement 对象作为注入点对象存入集合中
            currElements.add(new AutowiredMethodElement(method, required, pd));
         }
      });

      // 把父类要进行依赖注入的属性放前面,直到找到Object类这一层
      elements.addAll(0, currElements);
      targetClass = targetClass.getSuperclass();
   }
   while (targetClass != null && targetClass != Object.class);

   // 将所有的注入点elements集合封装为InjectionMetadata对象返回
   return InjectionMetadata.forElements(elements, clazz);
}


注入点进行注入

注入点进行注入是基于InstantiationAwareBeanPostProcessor接口的postProcessProperties()方法实现的。

所以在AutowiredAnnotationBeanPostProcessor类中的postProcessMergedBeanDefinition()方法中将寻找到的注入点存入injectionMetadataCache集合中。然后在调用postProcessProperties()进行进行实际的属性注入

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
   // 找注入点(所有被@Autowired注解了的Field或Method),此时就能够从injectionMetadataCache获取到值了
   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()方法还是和上面的一样,只是这次就能够从injectionMetadataCache获取到值了。重点看inject()注入的逻辑,这里其实就是遍历上一步寻找注入点时得到的集合,然后再继续调用element.inject(target, beanName, pvs);

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
   Collection<InjectedElement> checkedElements = this.checkedElements;
   // injectedElements属性值就是上一步寻找注入点时的结果
   Collection<InjectedElement> elementsToIterate =
         (checkedElements != null ? checkedElements : this.injectedElements);
   if (!elementsToIterate.isEmpty()) {
      // 遍历每个注入点进行依赖注入
      // @Resource注解才是对应的InjectedElement类;@Autowired注解对应的它的子类AutowiredFieldElement或AutowiredMethodElement,
      for (InjectedElement element : elementsToIterate) {
         element.inject(target, beanName, pvs);
      }
   }
}

所以如果是针对@Autowired注解,那么我们应该要看InjectedElement的子类AutowiredFieldElementAutowiredMethodElementinject()方法

首先是针对属性的依赖注入方法AutowiredFieldElement类的inject()方法,主要就是根据Field对象去BeanFactory中找到具体的值,然后赋值给这个属性

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {

   Field field = (Field) this.member;
   Object value;
   // 刚开始是没有缓存的,会直接走else语句段
   if (this.cached) {
      // 对于原型Bean,第一次创建的时候,也找注入点,然后进行注入,此时cached为false,注入完了之后cached为true
      // 第二次创建的时候,先找注入点(此时会拿到缓存好的注入点),也就是AutowiredFieldElement对象,此时cache为true,也就进到此处了
      // 注入点内并没有缓存被注入的具体Bean对象,而是beanName,这样就能保证注入到不同的原型Bean对象
      try {
         value = resolvedCachedArgument(beanName, this.cachedFieldValue);
      }
      catch (NoSuchBeanDefinitionException ex) {
         // Unexpected removal of target bean for cached argument -> re-resolve
         value = resolveFieldValue(field, bean, beanName);
      }
   }
   else {
      // 根据filed从BeanFactory中查到的匹配的Bean对象
      // resolveFieldValue()方法中最终会调用到resolveDependency()方法找对象
      value = resolveFieldValue(field, bean, beanName);
   }

   // 反射给filed赋值
   if (value != null) {
      ReflectionUtils.makeAccessible(field);
      field.set(bean, value);
   }
}

其实针对方法的AutowiredMethodElement类的inject()方法具体实现也类似,利用Method方法中的参数去BeanFactory中找到具体的值,然后在执行方法

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
   // 如果pvs中已经有当前注入点的值了,则跳过注入
   if (checkPropertySkipping(pvs)) {
      return;
   }
   Method method = (Method) this.member;
   Object[] arguments;
   // 缓存中找
   if (this.cached) {
      try {
         arguments = resolveCachedArguments(beanName);
      }
      catch (NoSuchBeanDefinitionException ex) {
         arguments = resolveMethodArguments(method, bean, beanName);
      }
   }
   else {
      // 利用Method对象取BeanFactory中找到相应的值
      arguments = resolveMethodArguments(method, bean, beanName);
   }
   if (arguments != null) {
      try {
         ReflectionUtils.makeAccessible(method);
         // 再执行方法
         method.invoke(bean, arguments);
      }
      catch (InvocationTargetException ex) {
         throw ex.getTargetException();
      }
   }
}

接下来就轮到了怎么根据Field和Method对象去BeanFactory中找值了,也就是resolveFieldValue()方法和resolveMethodArguments()方法,这两个方法最终都会调用resolveDependency()方法去找到最终要注入的对象



从BeanFactory中找注入对象

上面Spring原始依赖注入BY_TYPE方式,以及利用@Autowired注解加载属性或方法上,最终都是调用的DefaultListableBeanFactory类中的resolveDependency方法,去BeanFactory中找到要注入的值。

@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
      @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
   // 往descriptor中初始化方法参数名字发现器 用来获取方法入参名字的
   descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());

   // 所需要的类型是Optional,如果字段的类型或方法参数的类型是Optional会有一个单独了处理逻辑
   if (Optional.class == descriptor.getDependencyType()) {
      return createOptionalDependency(descriptor, requestingBeanName);
   }
   // 所需要的的类型是ObjectFactory,或ObjectProvider,也会有一个单独的处理逻辑
   else if (ObjectFactory.class == descriptor.getDependencyType() ||
         ObjectProvider.class == descriptor.getDependencyType()) {
      return new DependencyObjectProvider(descriptor, requestingBeanName);
   }
   else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
      return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
   }
   // 上面几种特殊情况可以不用太关注,大部分情况下我们的类型都不会是上面的那些情况,核心关注下面else语句段
   else {
      // 在属性或set方法参数前使用了@Lazy注解,那么则构造一个代理对象并返回,真正使用该代理对象时才进行类型筛选Bean
      Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
            descriptor, requestingBeanName);

      if (result == null) {
         // descriptor表示某个属性或某个set方法
         // requestingBeanName表示正在进行依赖注入的Bean
         result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
      }
      return result;
   }
}

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

   InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
   try {
      // 如果当前descriptor之前做过依赖注入了,则可以直接取shortcut了,相当于缓存
      Object shortcut = descriptor.resolveShortcut(this);
      if (shortcut != null) {
         return shortcut;
      }

      // 字段的类型或方法形参的类型
      Class<?> type = descriptor.getDependencyType();
      // 下面这个if逻辑是处理@Value注解的。获取@Value所指定的值
      Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
      if (value != null) {
         if (value instanceof String) {
            // 占位符填充(${XXX}) 就是用XXX作为key,去Environment对象中找对应的value,如果没有找到就直接返回${XXX}字符串
            String strVal = resolveEmbeddedValue((String) value);
            BeanDefinition bd = (beanName != null && containsBean(beanName) ?
                  getMergedBeanDefinition(beanName) : null);
            // 解析Spring表达式(#{})
            value = evaluateBeanDefinitionString(strVal, bd);
         }
         // 将value转化为descriptor所对应的类型
         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()));
         }
      }

      // 如果descriptor所对应的类型是数组、集合、Map这些,就将descriptor对应的类型所匹配的所有bean方法,不用进一步再根据beanName做筛选了
      Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
      if (multipleBeans != null) {
         return multipleBeans;
      }

      
      // 根据type去找bean。找到所有Bean,key是beanName, value有可能是bean对象,有可能是beanClass
      Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
      if (matchingBeans.isEmpty()) {
         // 根据type一个bean都没有找到, 同时required还为true,则抛异常
         if (isRequired(descriptor)) {
            raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
         }
         return null;
      }

      String autowiredBeanName;
      Object instanceCandidate;

      if (matchingBeans.size() > 1) {
         // 根据类型找到了多个Bean,进一步筛选出某一个, @Primary-->优先级最高--->name
         autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
         if (autowiredBeanName == null) {
            // 如果没有找打bean,同时required还为true,则抛异常
            if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
               return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
            }
            else {
               // In case of an optional Collection/Map, silently ignore a non-unique case:
               // possibly it was meant to be an empty collection of multiple regular beans
               // (before 4.3 in particular when we didn't even look for collection beans).
               return null;
            }
         }
         instanceCandidate = matchingBeans.get(autowiredBeanName);
      }
      else {
         // 表示根据type只找到了一个bean对象
         // We have exactly one match.
         Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
         autowiredBeanName = entry.getKey();
         instanceCandidate = entry.getValue();
      }

      // 记录匹配过的beanName
      if (autowiredBeanNames != null) {
         autowiredBeanNames.add(autowiredBeanName);
      }
      // 有可能筛选出来的是某个bean的类型,此处就进行实例化,调用getBean
      if (instanceCandidate instanceof Class) {
         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()方法是如何根据type找bean对象的

protected Map<String, Object> 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<String, Object> result = CollectionUtils.newLinkedHashMap(candidateNames.length);

   // 根据类型从resolvableDependencies中匹配Bean,resolvableDependencies中存放的是类型:Bean对象,比如BeanFactory.class:BeanFactory对象,在Spring启动时设置
   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;
         }
      }
   }

   // 依赖注入 注入自己这种情况下,如果一个type存在多个bean对象,优先考虑的是其他的bean对象
   for (String candidate : candidateNames) {
      // 如果不是自己,则判断该candidate到底能不能用来进行自动注入。isAutowireCandidate()采用了责任链设计模式
      // 因为我们可以使用@Bean注解的autowireCandidate=false来指定当前bean不能参与依赖注入
      if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
         // bean对象添加进result集合中
         addCandidateEntry(result, candidate, descriptor, requiredType);
      }
   }

   // 为空要么是真的没有匹配的,要么是匹配的自己
   if (result.isEmpty()) {
      // 需要匹配的类型是不是Map、数组之类的
      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);
         }
      }

      // 匹配的是自己,被自己添加到result中
      if (result.isEmpty() && !multiple) {
         for (String candidate : candidateNames) {
            if (isSelfReference(beanName, candidate) &&
                  (!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
                  isAutowireCandidate(candidate, fallbackDescriptor)) {
               addCandidateEntry(result, candidate, descriptor, requiredType);
            }
         }
      }
   }
   return result;
}


总结

  • Spring早期依赖注入的两种方式:BY_NAME 和 BY_TYPE

  • 寻找所有的注入点,AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition()

  • 为注入点赋值,入口

    AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement.inject()

    AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement.inject()

  • 处理@Value注解,DefaultListableBeanFactory.doResolveDependency()

  • 根据type,然后遍历所有的BeanDefinition,找到匹配的beanName集合。DefaultListableBeanFactory.findAutowireCandidates()

  • 判断1,处理@Bean注解的autowireCandidate=false,判断BeanDefinition中的autowireCandidate属性值

    SimpleAutowireCandidateResolver.isAutowireCandidate()

  • 判断2,处理泛型的情况 GenericTypeAwareAutowireCandidateResolver.isAutowireCandidate()

  • 判断3,处理@Qualifier注解,QualifierAnnotationAutowireCandidateResolver.isAutowireCandidate()

  • 如果经过上面三个筛选之后还剩下多个bean,进一步筛选@Primary–>优先级最高—>name DefaultListableBeanFactory.determineAutowireCandidate()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/15598.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

各大外卖平台占据共享经济市场主要份额,占比近50%

哈喽大家好&#xff0c;随着大量互联网用户和移动支付的普及、大量用户通过共享平台将闲置资源和服务与需求方进行匹配&#xff0c;实现了资源的高效利用和消费者福利的提升。在全球化驱动的新型消费需求以及政策支持下&#xff0c;共享经济正在向更加成熟和规范化的方向发展。…

瑞芯微RK3568智慧视频录像机NVR设备解决方案

NVR技术应用功能模式&#xff0c;较为灵活且能够在很大程度上满足当今视频监控系统功能需求。以NVR技术为核心的小型NVR方案&#xff0c;具有规模较小、操作灵活、使用方便、经济实用等优点&#xff0c;其前端主要配合高清视频摄像机支持8路720P的高清视频图像接入&#xff0c;…

13-NumPy

文章目录 一.基础1.Ndarray对象2.数据类型 二.数组1.数组属性&#xff08;1&#xff09;arange&#xff08;2&#xff09;shape&#xff08;3&#xff09;ndim&#xff08;4&#xff09;itemsize 2.创建数组&#xff08;1&#xff09;empty&#xff08;2&#xff09;zero&#…

Chat GPT在全球变暖中的潜在应用

01 摘要 气候变化是一个全球性的重大挑战&#xff0c;需要整合包括大气科学、海洋学和生态学在内的许多不同科学领域。解决这一问题的复杂性和规模需要利用先进的工具和技术来理解、建模和预测未来的气候状况。人工智能和自然语言处理技术&#xff0c;如Chat GPT&#xff0c;…

Maven 依赖下载失败解决方案——配置国内源 + 具体解决办法

目录 前言 一、配置 Maven 国内源 二、重新下载jar包 三、其他问题 前言 最近发现 spring-boot 框架更新到 2.7.11 了&#xff0c;由于以前一直使用的是 2.7.9 &#xff0c;所以一直出现依赖下载失败的问题&#xff0c;实际上这是由于 IDEA 会先加载之前下载好的依赖&#xf…

Linux操作系统命令大全

Linux是一种操作系统 Operating System 简称 OS &#xff0c;是软件的一部分&#xff0c;它是硬件基础上的第一层软件&#xff0c;是硬件和其它软件沟通的桥梁。 操作系统会控制其他程序运行&#xff0c;管理系统资源&#xff0c;提供最基本的计算功能&#xff0c;如管理及配置…

业内常用即时传输网盘

工具名称 业内常用即时传输网盘 功能简介 无需登录&#xff0c;短时间内有效&#xff0c;多用于传输小型敏感文件 外部链接 请见文内 内部网盘链接 在线站点&#xff0c;无网盘链接 使用说明 许多安全行内人士在团队内互传敏感文件时&#xff0c;为实现上传和下载文件…

现场工程师救火-UEFI(BIOS)节能设置导致金牌服务器只跑出龟速

近期协助出现场&#xff0c;解决了一个非常典型的UEFI 启动参数配置不当导致的服务器降效案例。错误的节能参数配置&#xff0c;导致价值几十万的服务器变成龟速服务器&#xff0c;并造成严重的生产事故。 1. 现象 朋友公司近期准备升级2010年就部署的服务器组&#xff0c;新…

《斯坦福数据挖掘教程·第三版》读书笔记(英文版) Chapter 2 MapReduce and the New Software Stack

来源&#xff1a;《斯坦福数据挖掘教程第三版》对应的公开英文书和PPT Chapter 2 MapReduce and the New Software Stack Computing cluster means large collections of commodity hardware, including conventional processors (“compute nodes”) connected by Ethernet …

centos8 mysql 主从复制

♥️作者:小刘在C站 ♥️个人主页:小刘主页 ♥️每天分享云计算网络运维课堂笔记,努力不一定有收获,但一定会有收获加油!一起努力,共赴美好人生! ♥️夕阳下,是最美的绽放,树高千尺,落叶归根人生不易,人间真情 目录 Linux centos8

使用D435i深度相机运行ORB-SLAM3

下载安装链接 下载ORB-SLAM3地址&#xff1a; git clone https://github.com/UZ-SLAMLab/ORB_SLAM3.git eigen3多版本安装&#xff1a;https://blog.csdn.net/weixin_41756645/article/details/129570141 ORB-SLAM2中eigen3版本为&#xff1a;3.2.10版本 ORB-SLAM3中eigen3版…

【分布式】一致性哈希和哈希槽

当我们拥有了多台存储服务器之后&#xff0c;现在有多个key&#xff0c;希望可以将这些个key均匀的缓存到这些服务器上&#xff0c;可以使用哪些方案呢&#xff1f; 1. 普通哈希取模法 1.1 直接哈希取模 这是一种最容易想到的方法&#xff0c;使用取模算法hash&#xff08;k…

AI绘图实战(七):室内设计线稿渲染、景观设计手绘稿改动、建筑照片转线稿|Stable Diffusion成为设计师生产力工具

S&#xff1a;AI能取代设计师么&#xff1f; I &#xff1a;至少在设计行业&#xff0c;目前AI扮演的主要角色还是超级工具&#xff0c;要顶替&#xff1f;除非甲方对设计效果无所畏惧~~ 预先学习&#xff1a; 安装及其问题解决参考&#xff1a;《Windows安装Stable Diffusion …

javaScript:cropperjs是一款非常强大却又简单的图片裁剪工具

cropperjs是一款非常强大却又简单的图片裁剪工具&#xff0c;它可以进行非常灵活的配置&#xff0c;支持手机端使用&#xff0c;支持包括IE9以上的现代浏览器。&#xff08;关键是使用方法简单&#xff0c;几行代码就可以搞定&#xff09; 官方github文档&#xff1a;GitHub -…

流程图拖拽视觉编程-流程编辑器

目录 一、简介 二、流程编辑器-视图实现 三、参考资料 一、简介 前期文章&#xff1a; 流程图拖拽视觉编程--概述_Jason~shen的博客-CSDN博客 本期内容&#xff1a; 本期将介绍流程编辑器模块的实现方法&#xff0c;效果图如下所示。该模块基于QT Graphics/View实现&…

使用FFMPEG库封装264视频和acc音频数据到MP4文件中

准备 ffmepeg 4.4 一段H264的视频文件 一段acc格式的音频文件 封装流程 1.使用avformat_open_input分别打开视频和音频文件&#xff0c;初始化其AVFormatContext&#xff0c;使用avformat_find_stream_info获取编码器基本信息 2.使用avformat_alloc_output_context2初始化…

solidity 安全 如何阻止重入攻击

什么是可重入攻击&#xff1f; 我们使用合约的过程中&#xff0c;经常会遇到这种情况&#xff0c;智能合约能够调用外部的合约&#xff1b;这些外部合约又可以回调到调用他们的智能合约&#xff1b;在这种情况下&#xff0c;我们说智能合约被重新输入&#xff0c;这种情况被称为…

Hive ---- Hive 安装

Hive ---- Hive 安装 1. Hive安装地址2. Hive安装部署1. 安装Hive2. 启动并使用Hive 3. MySQL安装1. 安装MySQL2. 配置MySQL3. 卸载MySQL说明 4. 配置Hive元数据存储到MySQL1. 配置元数据到MySQL2. 验证元数据是否配置成功3. 查看MySQL中的元数据 5. Hive服务部署1. hiveserver…

图像处理:均值滤波算法

目录 前言 概念介绍 基本原理 Opencv实现中值滤波 Python手写实现均值滤波 参考文章 前言 在此之前&#xff0c;我曾在此篇中推导过图像处理&#xff1a;推导五种滤波算法&#xff08;均值、中值、高斯、双边、引导&#xff09;。这在此基础上&#xff0c;我想更深入地研…

wvp开发环境搭建

代码下载地址 代码下载地址 https://gitee.com/pan648540858/wvp-GB28181-pro.git 开发工具 采用jetbrain idea 利用开发工具下载代码 文件-新建-来自版本控制的项目 url是上面的代码下载链接&#xff0c;点击克隆即可 下图是已经克隆并打开的代码 安装依赖环境 安装redi…