深度解读依赖注入DI源码

news2024/9/24 23:27:52

spring-framework-5.3.10 版本

依赖注入代码的入口在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean 。如果想搞清楚为什么是这里需要去学习下Bean的生命周期,这里就不介绍了。

@Autowired

@Autowired
private OrderService orderService;

使用@Autowired注解,在程序执行时会调用populateBean方法中的postProcessProperties

最终会进入到org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessProperties。首先会去查找注入点,注入点也就是需要进行自动注入的属性方法

findAutowiringMetadata 中会调用 buildAutowiringMetadata 这个就是寻找注入点最后核心的方法。

寻找注入点

先来看一下全貌,然后我们一起逐行进行分析。这段代码可以分成两大块14-30行用来寻找属性的注入点,33到60行用来寻找方法的注入点。

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
   // 如果一个Bean的类型是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
      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);
            // 构造注入点
            currElements.add(new AutowiredFieldElement(field, required));
         }
      });

      // 遍历targetClass中的所有Method
      ReflectionUtils.doWithLocalMethods(targetClass, 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);
               }
            }
            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);
}

3-5行 判断当前类是否不需要寻找注入点。底层判断逻辑代码如下

static boolean hasPlainJavaAnnotationsOnly(Class<?> type) {
   return (type.getName().startsWith("java.") || type == Ordered.class);
}

寻找属性注入点

14-30行用来寻找属性的注入点

  1. 14行 ReflectionUtils.doWithLocalFields 会遍历当前类里面的所有字段。

  1. 16行 然后去findAutowiredAnnotation 判断当前字段上是否存在@Autowired、@Value、@Inject中的其中一个,如果存在任意一个则当前字段判断为注入点。

  1. 19行 如果属性是static的不进行注入,因为在原型模式下,static属性多个对象赋值时会存在覆盖。

  1. 26行 查看当前属性是否要求必须注入,required默认为true。

  1. 28行 将找到的注入点放入currElements,最终通过67行 InjectionMetadata.forElements 封装成InjectionMetadata对象。

寻找方法注入点

33到60行用来寻找方法的注入点。寻找方法注入点和属性注入点类似。主要说明以下几个地方

35-38行 这里判断是否为桥接方法,并对桥接方法进行过滤。 这里主要是处理泛型接口的实现类中的注入,了解即可。

50行 这里即使方法上没有入参,如果添加了@Autowired注解方法也会执行。

注意第10-65行,是一个do while,看第63行可以理解,逻辑时先找自己的注入点,然后去找父类。知道找到所有注入点。

67行 InjectionMetadata.forElements 将属性和方法上的注入点,封装成InjectionMetadata对象,并返回

进行依赖注入

寻找到注入点以后,接下来就是对注入点的属性和方法进行依赖注入了。metadata.inject(bean, beanName, pvs); 实现依赖注入

同样的注入也分为属性注入和方法注入

属性注入

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

   Field field = (Field) this.member;
   Object value;
   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对象
      value = resolveFieldValue(field, bean, beanName);
   }

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

6-17行 先判断缓存里是否有,如果没有调用resolveFieldValue获取到属性值

24-26行 利用反射将属性值注入到属性

resolveFieldValue方法是注入的核心,我们进到这个方法里看看

@Nullable
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {

   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();
   Object value;
   try {
      value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
   }
   catch (BeansException ex) {
      throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
   }
   synchronized (this) {
      if (!this.cached) {
         Object cachedFieldValue = null;
         if (value != null || this.required) {
            cachedFieldValue = desc;
            // 注册一下beanName依赖了autowiredBeanNames,
            registerDependentBeans(beanName, autowiredBeanNames);
            if (autowiredBeanNames.size() == 1) {
               String autowiredBeanName = autowiredBeanNames.iterator().next();
               if (beanFactory.containsBean(autowiredBeanName) &&
                     beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
                  // 构造一个ShortcutDependencyDescriptor作为缓存,保存了当前filed所匹配的autowiredBeanName,而不是对应的bean对象(考虑原型bean)
                  cachedFieldValue = new ShortcutDependencyDescriptor(
                        desc, autowiredBeanName, field.getType());
               }
            }
         }
         this.cachedFieldValue = cachedFieldValue;
         this.cached = true;
      }
   }
   return value;
}

4行 生成依赖描述器

resolveDependency

12行 是一个核心方法resolveDependency。我们在进入这个方法来看看

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

   // 所需要的类型是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 {
      // 在属性或set方法上使用了@Lazy注解,那么则构造一个代理对象并返回,真正使用该代理对象时才进行类型筛选Bean
      Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
            descriptor, requestingBeanName);

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

6行 获取方法的入参名字

8-19行 处理一些特殊的情况。不做分析

22-28行 这里才是我们常用的情况

@Lazy注解

22行 判断属性上是否添加了@Lazy注解,或者方法参数前面是否添加了@Lazy注解。如果添加了@Lazy注解,说明属性不会在这里进行注入。而是等待真正使用的时候才进行注入,此时属性并没有真正注入,而是返回一个代理对象。在真正使用时通过代理对象进行依赖注入,并返回注入后的对象。

doResolveDependency方法

如果没有添加@Lazy注解,会进入到28行 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 {
      // 如果当前descriptor之前做过依赖注入了,则可以直接取shortcut了,相当于缓存
      Object shortcut = descriptor.resolveShortcut(this);
      if (shortcut != null) {
         return shortcut;
      }

      Class<?> type = descriptor.getDependencyType();
      // 获取@Value所指定的值
      Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
      if (value != null) {
         if (value instanceof String) {
            // 占位符填充(${})
            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方法,不用进一步做筛选了
      Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
      if (multipleBeans != null) {
         return multipleBeans;
      }

      // 找到所有Bean,key是beanName, value有可能是bean对象,有可能是beanClass
      Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
      if (matchingBeans.isEmpty()) {
         // 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) {
            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 {
         // 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);
   }
}

@Value解析

15-36行 是对@Value注解的解析

19行 占位符填充(${}) 从properties文件中或者运行时使用-D指定的环境变量中。以占位符作为key,读取值填充到属性中。

@Value("${user.name}")
private String name;

使用properties时需要引入

@PropertySource("classpath:spring.properties")
public class AppConfig {

23行 解析Spring表达式(#{}) 从spring容器中找到符合的bean

@Value("#{orderServie}") 
private OrderService orderService;

25-35行 是一个类型转化器,可以对@Value解析出来的值利用转化器转成目标属性的类型

38-42行 如果descriptor所对应的类型是数组、Map这些,就将descriptor对应的类型所匹配的所有bean方法,不用进一步做筛选了。例如

@Autowired
private Map<String,OrderService> orderServiceMap;

45行findAutowireCandidates根据传入的类型和beanName找到所需的Bean,Map<String, Object> 找到符合的Bean可能不止一个,这里String对应Bean的名字,Object对应的并不是Bean本身,而是Bean的Class,这样设计是因为我们找到了多个Bean以后,只需要对匹配的Bean进行实例化就可以了,多余的bean不需要处理。所以只取了class,没有取实例化以后的bean。

// 找到所有Bean,key是beanName, value有可能是bean对象,有可能是beanClass
 Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);

46-51行 如果没有找到bean,并且isRequired为true则抛异常,如果isRequired为false则返回null

      if (matchingBeans.isEmpty()) {
         // required为true,抛异常
         if (isRequired(descriptor)) {
            raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
         }
         return null;
      }

57-72行 如果找到了多个Bean,需要调用determineAutowireCandidate方法进行过滤,找到符合条件的唯一Bean

@Primary @Priority

determineAutowireCandidate中会根据 @Primary-->@Priority优先级最高--->name 的顺序取Bean。 @Priority只能写在类上。

如果获取不到判断是否isRequired为ture,逻辑和上面一样。

if (matchingBeans.size() > 1) {
         // 根据类型找到了多个Bean,进一步筛选出某一个, @Primary-->优先级最高--->name
         autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
         if (autowiredBeanName == null) {
            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);
      }

73-78行 如果只找到了唯一的bean,那么这个bean就是我们想要的了。

else {
         // We have exactly one match.
         Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
         autowiredBeanName = entry.getKey();
         instanceCandidate = entry.getValue();
      }

85-87行 后面的逻辑就是将筛选出来的bean对应的class进行实例化,然后将实例化以后的bean返回给属性进行注入

 // 有可能筛选出来的是某个bean的类型,此处就进行实例化,调用getBean
      if (instanceCandidate instanceof Class) {
         instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
      }

90-95行 处理只有名字,bean为null的特殊情况。

if (result instanceof NullBean) {
         if (isRequired(descriptor)) {
            raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
         }
         result = null;
      }

findAutowireCandidates

我们在回头看下45行findAutowireCandidates

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;
         }
      }
   }


   for (String candidate : candidateNames) {
      // 如果不是自己,则判断该candidate到底能不能用来进行自动注入
      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) {
         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;
}

5行 从spring容器中,通过单例池和BeanDefinitionMap中找到符合的Bean

10-21行 遍历 , Object> resolvableDependencies 中记录了一个Class对应的Bean对象是什么

24-28行 candidateNames中存储了符合条件的bean的名字。 如果是自己注入自己,例如下面这种,如果还存在另外一个UserService类型,优先使用非自己的bean进行注入。

public class UserService {

   @Autowired
   UserService userService;

isAutowireCandidate用来判断一个bean是否可以进行依赖注入。这里用到了责任链

org.springframework.beans.factory.support.SimpleAutowireCandidateResolver#isAutowireCandidate

org.springframework.beans.factory.support.GenericTypeAwareAutowireCandidateResolver#isAutowireCandidate 处理泛型

org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#isAutowireCandidate 处理Qualifier

@Bean(autowireCandidate = false)
public UserService userService() {
   return new UserService();
}

32-56行 判断是否存在符合条件的bean,如果没有找到符合条件的bean.在看看自己是否是符合条件的。因为在24-28行中排出了自己。

方法注入

@Override
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) {
         // Unexpected removal of target bean for cached argument -> re-resolve
         arguments = resolveMethodArguments(method, bean, beanName);
      }
   }
   else {
      arguments = resolveMethodArguments(method, bean, beanName);
   }
   if (arguments != null) {
      try {
         ReflectionUtils.makeAccessible(method);
         method.invoke(bean, arguments);
      }
      catch (InvocationTargetException ex) {
         throw ex.getTargetException();
      }
   }
}

方法注入和属性注入类似,只是方法的入参可能是多个,所以会遍历每一个参数去获取参数值,然后注入。

resolveMethodArguments方法中同样会调用resolveDependency。这里的逻辑就和上面一样了。

Autowire.BY_NAME

找出对象中所有的set方法,然后将setXXX后面的XXX作为属性名称,在容器中取得Bean进行注入。

@ComponentScan("com.mtb")
public class AppConfig {
   @Bean(autowire = Autowire.BY_NAME)
   public UserService userService() {
      return new UserService();
   }
}
@Component
public class UserService {

   private OrderService orderService;

   public void test() {
      System.out.println(orderService);
   }

   public void setOrderService(OrderService orderService) {
      this.orderService = orderService;
   }
}

使用这种方式会进入org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#autowireByName

进入autowireByName后,会通过unsatisfiedNonSimpleProperties拿到bean中需要注入的所有属性名字

进入以后,先获取属性描述器

PropertyDescriptor中有几个属性:

name:这个name并不是方法的名字,而是拿方法名字进过处理后的名字
如果方法名字以“get”开头,比如“getXXX”,那么name=XXX
如果方法名字以“is”开头,比如“isXXX”,那么name=XXX
如果方法名字以“set”开头,比如“setXXX”,那么name=XXX
readMethodRef:表示get方法的Method对象的引用
readMethodName:表示get方法的名字
writeMethodRef:表示set方法的Method对象的引用
writeMethodName:表示set方法的名字
propertyTypeRef:如果有get方法那么对应的就是返回值的类型,如果是set方法那么对应的就是set方法中唯一参数的类型

这里需要注意getPropertyDescriptors获取的不是对象中的属性,而是对象中的set方法,然后将set方法后面内容作为属性名。例如userService中的setOrderService,会把set后面的orderSercie作为属性名字。所以使用byName时,必须要有对应的set方法。

通过debug我们可以看到pds中解析出来了orderService属性

pvs.contains(pd.getName()) 如果在依赖注入前,已经注入了值(例如程序员使用了beanDefinition设置了值),那么不在自动注入。

BeanUtils.isSimpleProperty(pd.getPropertyType()) 如果是简单类型也不注入

简单类型如下:

public static boolean isSimpleValueType(Class<?> type) {
   return (Void.class != type && void.class != type &&
         (ClassUtils.isPrimitiveOrWrapper(type) ||
         Enum.class.isAssignableFrom(type) ||
         CharSequence.class.isAssignableFrom(type) ||
         Number.class.isAssignableFrom(type) ||
         Date.class.isAssignableFrom(type) ||
         Temporal.class.isAssignableFrom(type) ||
         URI.class == type ||
         URL.class == type ||
         Locale.class == type ||
         Class.class == type));
}

执行完unsatisfiedNonSimpleProperties方法后,获取到了所有需要注入的属性。然后通过getBean获取bean,加入到pvs中。

最终会在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean 方法中调用applyPropertyValues 完成注入

Autowire.BY_TYPE

Autowire.BY_TYPE的流程与BY_NAME相似。 byType或通过入参去查找对象。

@Resource

寻找注入点

@resource注解通过org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#findResourceMetadata查找注入点 ,调用buildResourceMetadata查找添加了@Resouce注解的属性或方法。 如果属性是static的会报错。

进行依赖注入

流程和@Autowired类似,核心调用方法如下

org.springframework.beans.factory.annotation.InjectionMetadata.InjectedElement#inject

org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.ResourceElement#getResourceToInject

org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.ResourceElement#ResourceElement

public ResourceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {
   super(member, pd);
   Resource resource = ae.getAnnotation(Resource.class);
   String resourceName = resource.name();
   Class<?> resourceType = resource.type();

   // 使用@Resource时没有指定具体的name,那么则用field的name,或setXxx()中的xxx
   this.isDefaultName = !StringUtils.hasLength(resourceName);
   if (this.isDefaultName) {
      resourceName = this.member.getName();
      if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {
         resourceName = Introspector.decapitalize(resourceName.substring(3));
      }
   }
   // 使用@Resource时指定了具体的name,进行占位符填充
   else if (embeddedValueResolver != null) {
      resourceName = embeddedValueResolver.resolveStringValue(resourceName);
   }

   // @Resource除开可以指定bean,还可以指定type,type默认为Object
   if (Object.class != resourceType) {
      // 如果指定了type,则验证一下和field的类型或set方法的第一个参数类型,是否和所指定的resourceType匹配
      checkResourceType(resourceType);
   }
   else {
      // No resource type specified... check field/method.
      resourceType = getResourceType();
   }
   this.name = (resourceName != null ? resourceName : "");
   this.lookupType = resourceType;

   String lookupValue = resource.lookup();
   this.mappedName = (StringUtils.hasLength(lookupValue) ? lookupValue : resource.mappedName());

   Lazy lazy = ae.getAnnotation(Lazy.class);
   this.lazyLookup = (lazy != null && lazy.value());
}

org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#autowireResource

protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
      throws NoSuchBeanDefinitionException {

   Object resource;
   Set<String> autowiredBeanNames;
   String name = element.name;

   if (factory instanceof AutowireCapableBeanFactory) {
      AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;
      DependencyDescriptor descriptor = element.getDependencyDescriptor();

      // 假设@Resource中没有指定name,并且field的name或setXxx()的xxx不存在对应的bean,那么则根据field类型或方法参数类型从BeanFactory去找
      if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
         autowiredBeanNames = new LinkedHashSet<>();
         resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
         if (resource == null) {
            throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
         }
      }
      else {
         resource = beanFactory.resolveBeanByName(name, descriptor);
         autowiredBeanNames = Collections.singleton(name);
      }
   }
   else {
      resource = factory.getBean(name, element.lookupType);
      autowiredBeanNames = Collections.singleton(name);
   }

   if (factory instanceof ConfigurableBeanFactory) {
      ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;
      for (String autowiredBeanName : autowiredBeanNames) {
         if (requestingBeanName != null && beanFactory.containsBean(autowiredBeanName)) {
            beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
         }
      }
   }

   return resource;
}

@Resource和@Autowired的区别

@Resource 先byName再byType , @Autowired 先byType 再byName

@Resource 是jdk的注解,@Autowired 是spring的注解

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

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

相关文章

电子科技大学操作系统期末复习笔记(五):文件管理

目录 前言 文件管理&#xff1a;基础 基本概念 文件 文件系统 文件系统的实现模型 文件的组成 文件名 文件分类 文件结构 逻辑结构 物理结构 练习题 文件管理&#xff1a;目录 文件控制块FCB FCB&#xff1a;File Control Block FCB信息 目录 基本概念 目…

CAN通信笔记-位时间、Tq及采样点同步

本文框架1.前言2. 位时间2.1 位时间定义2.2 位时间计算3. Tq3.1 Tq的计算3.1.1 举个例子3.2 位时间与Tq的换算4. 采样点同步4.1 硬同步4.2 重同步4.2.1 延长PBS1的重同步4.2.2 缩短PBS2的重同步1.前言 本篇记录些关于CAN的一些学习笔记&#xff0c;说实话CAN协议发展的已经非常…

【项目设计】—— 负载均衡式在线OJ平台

目录 一、项目的相关背景 二、所用技术栈和开发环境 三、项目的宏观结构 四、compile_server模块设计 1. 编译服务&#xff08;compiler模块&#xff09; 2. 运行服务&#xff08;runner模块&#xff09; 3. 编译并运行服务&#xff08;compile_run模块&#xff09; 4…

MicroBlaze系列教程(6):AXI_IIC的使用(24C04 EEPROM)

文章目录 @[toc]AXI_IIC简介MicroBlaze硬件配置常用函数使用示例波形实测参考资料工程下载本文是Xilinx MicroBlaze系列教程的第6篇文章。 AXI_IIC简介 一般情况下,使用FPGA实现I2C协议主要有两种方式:一种是基于Verilog实现起始位、停止位、ACK产生和判断、数据的发送和接收…

1.HTTP及Template介绍

目录 来源 介绍 模板与渲染 Go语言的模板引擎 模板引擎的使用 定义模板文件 解析模板文件 模板渲染 基本示例 模板语法 {{.}} 注释 pipeline 变量 移除空格 条件判断 range with 预定义函数 比较函数 自定义函数 模板的嵌套template block 修改默认的标…

加油站会员管理小程序实战开发教程13

我们上一篇讲解了会员注册的功能,本篇我们介绍一下会员开卡的功能。 会员注册之后,可以进行开卡的动作。一个会员可以有多张会员卡,在微搭中用来描述这种一对多的关系的,我们用关联关系来表达。 登录微搭的控制台,点击数据模型,点击新建数据模型 输入数据源的名称会员卡…

基于 Debain11 构建 asp.net core 6.x 的基础运行时镜像

基于 Debain11 构建 asp.net core 6.x 的基础运行时镜像Linux 环境说明Debian 简介Debian 发行版本关于 Debian 11Linux 常用基础工具Dockerfile 中 RUN 指令RUN 语法格式RUN 语义说明编写 Dockerfile 构建 Runtime 基础镜像ASP.NET Core Runtime 基础镜像Dockerfile 编写Windo…

sklearn主成分分析PCA

文章目录基本原理PCA类图像降维与恢复基本原理 PCA&#xff0c;即主成分分析(Principal components analysis)&#xff0c;顾名思义就是把矩阵分解成简单的组分进行研究&#xff0c;而拆解矩阵的主要工具是线性变换&#xff0c;具体形式则是奇异值分解。 设有mmm个nnn维样本X…

【面试题】数组reduce的用法

1. 对数组求和 传统的数组求和方式需要使用forEach循环遍历数组中的每一个元素&#xff0c;然后累加。然而这种方式需要新增一个用于存储累加结果的变量。 function sum(arr) {let res 0arr.forEach(element > res res element);return res }还可以通过数组的reduce方法…

算法笔记(九)—— 暴力递归

暴力递归&#xff08;尝试&#xff09; 1. 将问题转化为规模缩小了的同类问题子问题 2. 有明确的不需要的继续递归的条件 3. 有当得到子问题结果之后的决策过程 4. 不记录每一个子问题的解 Question&#xff1a;经典汉诺塔问题 1. 理解清楚&#xff0c;基础三个圆盘的移动…

2.5|iot|嵌入式Linux系统开发与应用|第4章:Linux外壳shell脚本程序编程

1.shell基础 Shell是Linux操作系统内核的外壳&#xff0c;它为用户提供使用操作系统的命令接口。 用户在提示符下输入的每个命令都由shell先解释然后发给Linux内核&#xff0c;所以Linux中的命令通称为shell命令。 通常我们使用shell来使用Linux操作系统。Linux系统的shell是…

高斯课堂 计算机网络(上)

第一章、概述 0、第一章导图 1、计算机网络概述 &#xff08;1&#xff09;计算机网络发展历史1&#xff1a;ARPANET->互联网 小写internet是一个宽泛的概念&#xff0c;指的就是互联网 大写Internet是一个专有名词&#xff0c;指的就是我们现在所使用的这样一个全球最大的…

Python(1)变量的命名规则

目录 1.变量的命名原则 3.内置函数尽量不要做变量 4.删除变量和垃圾回收机制 5.结语 参考资料 1.变量的命名原则 ①由英文字母、_(下划线)、或中文开头 ②变量名称只能由英文字母、数字、下画线或中文字所组成。 ③英文字母大小写不相同 实例&#xff1a; 爱_aiA1 print(…

2023VNCTF的两道(暂时)

from http://v2ish1yan.top/2023/02/19/%E6%AF%94%E8%B5%9Bwp/2023vnctf/ 比赛的时候在回学校的路上&#xff0c;所以没有打&#xff0c;听说质量挺高&#xff0c;赛后做一下 象棋王子 一个普通的js游戏&#xff0c;玩过关了就给flag&#xff0c;所以flag肯定在前端源码里 这…

设计模式之观察者模式与访问者模式详解和应用

目录1.访问者模式详解1.1 访问者模式的定义1.1.1 访问者模式在生活中的体现1.1.2 访问者模式的适用场景1.2 访问者模式的通用实现1.3 访问者模式的使用案例之KPI考核1.3.1 类图设计1.3.2 代码实现1.4 访问者模式扩展---分派1.4.1 java中静态分派示例代码1.4.2 java中动态分派1.…

C语言 基于Ncurse库的贪吃蛇游戏项目

为了敲键盘及时响应&#xff0c;需要用到ncurse 测试代码&#xff1a; ncurse1.c /* ncurse1.c */ #include <curses.h> //ncurse的头文件。int main() {char c;int i 0;//ncurse界面的初始化函数。initscr(); for(i0;i<2;i){c getch();printw("\n");//…

一起学 pixijs(2):修改图形属性

大家好&#xff0c;我是前端西瓜哥。 我们做动画、游戏、编辑器&#xff0c;需要根据用户的交互等操作&#xff0c;去实时地改变图形的属性&#xff0c;比如位置&#xff0c;颜色等信息。今天西瓜哥带大家来看看在 pixijs 怎么修改图形的属性。 因为 pixijs 的底层维护了图形…

2023年美赛C题Wordle预测问题三、四建模及Python代码详细讲解

更新时间:2023-2-19 16:30 相关链接 &#xff08;1&#xff09;2023年美赛C题Wordle预测问题一建模及Python代码详细讲解 &#xff08;2&#xff09;2023年美赛C题Wordle预测问题二建模及Python代码详细讲解 &#xff08;3&#xff09;2023年美赛C题Wordle预测问题三、四建模…

Android 基础知识4-2.8 TableLayout(表格布局)详解

一、TableLayout的概述 表格布局是以行数和列数来确定位置进行排列。就像一间教室&#xff0c;确定好行数与列数就能让同学有序入座。 注意&#xff1a;我们需要先添加<TableRow容器&#xff0c;每添加一个就会多一行&#xff0c;然后再往<TableRow容器中添加其它组件。…