Spring 依赖注入源码

news2024/11/25 2:53:55

文章目录

  • 依赖注入
    • 原始依赖注入方式
    • 注解方式
      • 寻找注入点
      • 注入点进行注入
    • 从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()

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Java校招面试】基础知识(二)——Spring Framework AOP

目录 前言一、Spring Framewwork基础知识二、Spring AOP基础概念1. 切面&#xff08;Aspect&#xff09;2. 织入&#xff08;Weaving&#xff09;3. 增强&#xff08;Advice&#xff09;4. 动态代理 三、JDK动态代理1. 基本用法2. 原理分析 四、CGLib动态代理1. 基本用法2. 原理…

【五一创作】使用Resnet残差网络对图像进行分类(猫十二分类,模型定义、训练、保存、预测)(二)

使用Resnet残差网络对图像进行分类 &#xff08;猫十二分类&#xff0c;模型定义、训练、保存、预测&#xff09;(二&#xff09; 目录 &#xff08;6&#xff09;、数据集划分 &#xff08;7&#xff09;、训练集增强 &#xff08;8&#xff09;、装载数据集 &#xff08…

山东专升本计算机第十一章-新一代信息技术

新一代信息技术 物联网 概念 物联网就是物物相连的互联网&#xff0c;其核心和基础仍然是互联网 计算机&#xff0c;互联网之后信息产业发展的第三次浪潮 推入人类进入智能时代&#xff0c;又称物联时代 三大特征 全面感知 可靠传递 智能处理 • 物联网的最核心 技术架…

阿里云g8i服务器ECS通用型服务器CPU处理器性能测评

阿里云服务器ECS通用型实例规格族g8i采用2.7 GHz主频的Intel Xeon(Sapphire Rapids) Platinum 8475B处理器&#xff0c;3.2 GHz睿频&#xff0c;g8i实例采用阿里云全新CIPU架构&#xff0c;可提供稳定的算力输出、更强劲的I/O引擎以及芯片级的安全加固。阿里云百科分享阿里云服…

JavaScript 入门(1)

script 标签 <scrtipt> 标签可以插入到HTML中的任何位置在很老的代码中需使用type属性&#xff0c;但是现在的代码中不需要 <script type"text/javascript"><!-- ... //--></script>外部脚本 通过src 属性将脚本添加到HTML中 <script …

Maven的全面讲解及如何安装使用

Maven是一种流行的Java项目管理工具&#xff0c;可用于构建、测试、打包和部署Java应用程序。本文将介绍Maven的概念、安装配置、使用方法、生命周期以及IDEA集成Maven的方法。 Maven的概念 Maven是一种基于项目对象模型&#xff08;POM&#xff09;的构建工具。POM是一个XML…

【C++】位运算类题目总结

文章目录 一. 位运算符脑图二. 相关题目1. 统计二进制数中0的个数2. 数组中只出现一次的数字3. 数组中只出现一次的数字 II4. 不用加减乘除做加法 一. 位运算符脑图 二. 相关题目 1. 统计二进制数中0的个数 解题思路&#xff1a;x & (x-1)&#xff1b;它的作用是每次循环…

系统集成项目管理工程师 笔记(第18章:项目风险管理)

文章目录 18.1.2 风险的分类 54318.1.3 风险的性质 544项目风险管理6个过程&#xff08;风险管理、识别风险、实施定性风险分析、实施定量风险分析、规划风险应对、控制风险&#xff09;组织和干系人的风险态度影响因素18.3.3 规划风险管理的输出 550风险识别的原则18.4.2 识别…

针对Vue前后端分离项目的渗透思路

引言 在目前的开发环境下&#xff0c;越来越多的厂商选择 Vue.js 来实现前端功能的编写&#xff0c;且成熟的前端框架已经可以实现后端代码实现的功能&#xff0c;导致后端目前只负责提供 Api 接口和文档&#xff0c;方便前端的同时去调用。本文主要介绍如何针对这类前后端分离…

如何利用几何坐标变换后纠正技术实现倾斜摄影三维模型数据拼接?

如何利用几何坐标变换后纠正技术实现倾斜摄影三维模型数据拼接&#xff1f; 倾斜摄影三维模型数据拼接是指将多个倾斜摄影数据集合并为一个完整的三维模型。在这个过程中&#xff0c;由于不同数据集之间的相对位置和姿态不同&#xff0c;需要进行几何坐标变换以实现数据拼接。…

借用AI工具为视频添加中文字幕,消除语言障碍,母语环境最快速地学习

由于chatgpt的启动&#xff0c;感觉语言已经完全不会成为学习的障碍&#xff0c;突发奇想&#xff0c;在我们查看youtube视频的时候&#xff0c;有没有方便的工具能够将其字幕翻译为中文。这样能够极大提高在youtube学习的效率&#xff0c;于是顺手问了一下ChatGPT&#xff0c;…

Nginx—在linux的ubuntu系统上的安装使用

前言: 有关Nginx的基础知识和使用都在这里Nginx简介和快速入门_北岭山脚鼠鼠的博客-CSDN博客 常用命令: cd /usr/local/nginx/sbin/ ./nginx 启动 ./nginx -s stop 停止 ./nginx -s quit 安全退出 ./nginx -s reload 重新加载配置文件(常用) //在修改配置文件之后使用 p…

教你部署chatgpt商业版源码,支持卡密开通国内使用

教你部署chatgpt商业版源码&#xff0c;支持卡密开通国内使用 当今&#xff0c;人工智能技术在各个领域的应用越来越广泛&#xff0c;其中自然语言处理是非常重要的一环。OpenAI 的 GPT 模型是自然语言处理领域的一项重要技术&#xff0c;它可以根据已有的文本数据&#xff0c;…

Java 怎样实现代理模式,有什么优缺点

一、介绍 代理模式是一种常见的设计模式&#xff0c;它可以为其他对象提供一种代理以控制对这个对象的访问。代理对象具有与被代理对象相同的接口&#xff0c;客户端无需知道代理对象和被代理对象的区别。代理模式可以应用于各种不同的场景&#xff0c;例如远程代理、虚拟代理…

Ubantu docker学习笔记(九)容器监控 自带的监控+sysdig+scope+cAdvisor+prometheus

文章目录 一、Docker命令监控二、Sysdig2.1介绍2.2 基本操作2.2.1 切换视图2.2.2 查看标签含义2.2.3 排序2.2.4 查看内部进程2.2.5 查找2.2.6 暂停2.2.7 上一级2.2.8 退出 三、Weave Scope3.1介绍3.2基本操作3.2.1 显示容器3.2.2 选择容器3.2.3 按照CPU使用情况排序3.2.4 控制容…

手动开发 简单的 Spring 基于 XML 配置的程序

目录 手动开发- 简单的 Spring 基于 XML 配置的程序 需求说明 思路分析 WyxApplicationContextTest xml配置 注意 手动开发- 简单的 Spring 基于 XML 配置的程序 需求说明 1. 自己写一个简单的 Spring 容器, 通过读取 beans.xml&#xff0c;获取第 1 个 JavaBean: Mon…

【建议收藏】Pandas(一)——初见Series

文章目录 &#x1f4da;引言&#x1f4d6;库的安装以及一些说明&#x1f4d1;库的安装&#x1f4d1;一些说明 &#x1f4d6;Series&#x1f4d1;创建一个Series&#x1f516;从列表创建Series&#x1f516;从字典创建Series&#x1f516;标量创建Series &#x1f4d1;Series的特…

SpringSecurity认证原理和自定义认证

认证原理和自定义认证 认证配置表单认证注销登录前后端分离认证添加验证码 自定义认证 自定义资源权限规则 /index 公共资源/hello … 受保护资源 权限管理 在项目中添加如下配置就可以实现对资源权限规则设定: Configuration public class WebSecurityConfigurer extend…

node笔记_http服务搭建(渲染html、json)

文章目录 ⭐前言⭐初始化项目调整npm 的script运行入口搭建hello world的http服务npm run dev执行主函数的http服务 ⭐http返回类型html模板文件返回安装express渲染html的字符串 渲染html文件 sendFile渲染json返回数据类型 res.json ⭐结束 ⭐前言 大家好&#xff0c;我是ym…

CTF权威指南 笔记 -第二章二进制文件- 2.2 -ELF文件格式

目录 ELF的文件类型 ELF文件的结构 ELF文件头 节头表 代码节 数据节和只读数据节 bss节 字符串表 符号表 重定位 可执行文件的装载 常见的段 ELF就是可执行可连接格式 为linux运行文件格式 ELF的文件类型 我们使用复杂的例子进行演示 #include<stdio.h>int gl…