Spring中@Autowired与@Resource自动注入实现原理

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Spring中@Autowired与@Resource自动注入实现原理

关联博文

Spring后置处理器中的InstantiationAwareBeanPostProcessor详解

Spring中Bean实例化过程中的initializeBean方法

Spring中Bean实例化过程中的populateBean方法

Spring中@Autowired与@Resource自动注入实现原理

Spring中如何获取到一个Bean实例?


从autowiring使用上可以知道,这个autowiring属性在对Bean属性进行依赖注入时起作用。而这是在populateBean中实现的。也就是说,对属性autowiring的处理是populateBean的一部分。在前面我们分析Spring中Bean实例化过程中的populateBean方法可以看到自动注入的解析出现在两个部分。第一部分:

// AbstractAutowireCapableBeanFactory#populateBean
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
  MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
  // Add property values based on autowire by name if applicable.
  if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
    autowireByName(beanName, mbd, bw, newPvs);
  }
  // Add property values based on autowire by type if applicable.
  if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
    autowireByType(beanName, mbd, bw, newPvs);
  }
  pvs = newPvs;
}

第二部分:

InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);


在第一部分为解析自动注入标识resolvedAutowireMode,默认值为AutowireCapableBeanFactory.AUTOWIRE_NO也就是0。当其为0时,不会执行autowireByName或者autowireByType逻辑。


postProcessProperties则可以理解为一种补偿机制,比如AutowiredAnnotationBeanPostProcessor的该方法,会尝试解析@Autowired注解触发依赖Bean的获取过程。


接下来我们从源码角度分析这两部分的流程。

【1】autowireByName和autowireByType

① autowireByName


当resolvedAutowireMode为1时,即AUTOWIRE_BY_NAME将会触发autowireByName(beanName, mbd, bw, newPvs);

方法源码如下:

//AbstractAutowireCapableBeanFactory#autowireByName
protected void autowireByName(
    String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// 获取未满足的非简单类型的属性名称
  String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
  for (String propertyName : propertyNames) {
  // 如果当前容器包含该属性名称对应的bean
    if (containsBean(propertyName)) {
    // 触发Bean的获取
      Object bean = getBean(propertyName);
      //更新pvs
      pvs.add(propertyName, bean);
      // 注册记录beanName与依赖 bean名称
      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");
      }
    }
  }
}

方法如上所示,获取需要解析的依赖bean。遍历循环尝试从容器中获取bean,然后更新到pvs中。最后调用registerDependentBean方法进行beanName与依赖bean名称留存记录。

② registerDependentBean



registerDependentBean方法如下所示,其使用dependentBeanMapdependenciesForBeanMap记录了beanName都被依赖了哪些bean和dependentBeanName都依赖了哪些bean。

public void registerDependentBean(String beanName, String dependentBeanName) {
  String canonicalName = canonicalName(beanName);
  synchronized (this.dependentBeanMap) {
    Set<String> dependentBeans =
        this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
    if (!dependentBeans.add(dependentBeanName)) {
      return;
    }
  }
  synchronized (this.dependenciesForBeanMap) {
    Set<String> dependenciesForBean =
        this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
    dependenciesForBean.add(canonicalName);
  }
}


在DefaultSingletonBeanRegistry中维护了一系列final map。其中dependentBeanMap 表示 beanName---哪些bean依赖了beanName,dependenciesForBeanMap 表示 beanName---beanName依赖了哪些bean。


/** Map between dependent bean names: bean name to Set of dependent bean names. */
private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);
/** Map between depending bean names: bean name to Set of bean names for the bean's dependencies. */
private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);

③ autowireByType

// AbstractAutowireCapableBeanFactory#autowireByType
protected void autowireByType(
    String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
  TypeConverter converter = getCustomTypeConverter();
  if (converter == null) {
    converter = bw;
  }
  Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
  // 获取未满足的非简单类型的bean名称/属性名称,
  //如创建我们的XXXMapper时会解析sqlSessionFactory、sqlSessionTemplate
  String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
  // 遍历循环解析
  for (String propertyName : propertyNames) {
    try {
      // 获取属性描述符
      PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
      // Don't try autowiring by type for type Object: never makes sense,
      // even if it technically is a unsatisfied, non-simple property.
      // 如果属性类型是Object,直接抛出异常
      if (Object.class != pd.getPropertyType()) {
        // 获取写方法参数对象,就是setXXXXX方法的参数对象
        MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
        // Do not allow eager init for type matching in case of a prioritized post-processor.
        // 判断是否为PriorityOrdered对象,即可以忽略order排序规则
        // 如果是PriorityOrdered则eager为false,否则为true。
        boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
        DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
      // 核心方法,解析依赖
        Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
    // 如果解析到依赖对象,比如sqlSessionFactory,那么放到pvs中
        if (autowiredArgument != null) {
          pvs.add(propertyName, autowiredArgument);
        }
        for (String autowiredBeanName : autowiredBeanNames) {
        //该方法前面提到过,注册记录bean与依赖bean的关系
          registerDependentBean(autowiredBeanName, beanName);
          if (logger.isTraceEnabled()) {
            logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
                propertyName + "' to bean named '" + autowiredBeanName + "'");
          }
        }
        autowiredBeanNames.clear();
      }
    }
    catch (BeansException ex) {
      throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
    }
  }
}


PropertyDescriptor 属性描述符。其包括属性名称、读方法、写方法、属性类型等。


MethodParameter,方法参数类型。其包括方法调用类、所属类、参数类型、参数个数、方法名称、方法返回类型、参数注解、异常类型等等。


如上代码所示,这里会解析得到propertyNames然后遍历解析依赖,之后会同autowireByName一样调用registerDependentBean方法注册记录bean与依赖bean的关系。


那么如何解析依赖呢?我们继续往下看。

④ 依赖解析resolveDependency

继续分析autowireByType,这部分我们分析依赖如何解析的。如下是DefaultListableBeanFactory的resolveDependency方法,这也是依赖解析的核心方法。在下文AutowiredAnnotationBeanPostProcessor的inject同样流转到了该方法。

public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
    @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// 默认是DefaultParameterNameDiscoverer,在分析springmvc流程中我们也提到过
  descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
// 判断依赖类型,通常这里是parameterType
  if (Optional.class == descriptor.getDependencyType()) {
    return createOptionalDependency(descriptor, requestingBeanName);
  }
  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 {
  // 这里是核心入口,这里是ContextAnnotationAutowireCandidateResolver
  // 判断是否为Lazy,如果是则使用ProxyFactory创建代理
    Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
        descriptor, requestingBeanName);
    if (result == null) {
    // 如果非Lazy,则进入实际依赖解析过程
      result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
    }
    return result;
  }
}

如上代码所示,首先设置ParameterNameDiscoverer,默认是DefaultParameterNameDiscoverer。然后判断依赖类型,根据依赖类型进行不同的处理。其中在最后一部分中会判断是否为Lazy,如果是Lazy则使用ProxyFactory创建代理返回。如果不是Lazy则进入实际依赖解析过程。


Lazy时,创建代理的过程可以参考方法ContextAnnotationAutowireCandidateResolver的buildLazyResolutionProxy方法。关于AutowireCandidateResolver

如下所示,DefaultListableBeanFactory内部维护了该成员默认是SimpleAutowireCandidateResolver。

private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();


但是在AnnotationConfigUtils的registerAnnotationConfigProcessors方法中会为容器设置解析器为ContextAnnotationAutowireCandidateResolver,这整个候选解析器是QualifierAnnotationAutowireCandidateResolver的子类。


我们继续看public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException 方法,这是实际解析依赖的入口。

public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
    @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
  InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
  try {
    Object shortcut = descriptor.resolveShortcut(this);
    if (shortcut != null) {
      return shortcut;
    }
//获取依赖类型,比如interface org.apache.ibatis.session.SqlSessionFactory
    Class<?> type = descriptor.getDependencyType();
  // 这部分处理 @Value 注解
  // value如${com.jane.file.baseFilePath}
    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);
        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()));
      }
    }
// 处理集合类型,比如Array Map Collection
    Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
    if (multipleBeans != null) {
      return multipleBeans;
    }
// 得到候选的、匹配的bean class实例:beanName---bean class 对象
    Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
    if (matchingBeans.isEmpty()) {
    // 如果为空且required,则抛出异常NoSuchBeanDefinitionException
      if (isRequired(descriptor)) {
        raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
      }
      return null;
    }
    String autowiredBeanName;
    Object instanceCandidate;
    if (matchingBeans.size() > 1) {
    // 如果有多个,则根据@Primary和@Priority进行抉择
      autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
      if (autowiredBeanName == null) {
       //如果抉择不出,则可能抛出异常NoUniqueBeanDefinitionException
        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();
      // 解析得到的依赖bean名称
      autowiredBeanName = entry.getKey();
      // 解析得到的依赖bean实例-Class对象哦,还需要进一步解析
      instanceCandidate = entry.getValue();
    }
    if (autowiredBeanNames != null) {
    // 放入autowiredBeanNames,如sqlSessionFactory
      autowiredBeanNames.add(autowiredBeanName);
    }
    // 如果实例是Class对象,则解析为真实的Bean实例对象
    if (instanceCandidate instanceof Class) {
      // beanFactory.getBean(beanName); 也就是getBean的过程
      instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
    }
    Object result = instanceCandidate;
    if (result instanceof NullBean) {
      if (isRequired(descriptor)) {
      // 抛出NoSuchBeanDefinitionException
        raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
      }
      result = null;
    }
    if (!ClassUtils.isAssignableValue(type, result)) {
    // 抛出BeanNotOfRequiredTypeException
      throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
    }
    return result;
  }
  finally {
    ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
  }
}

如上代码所示,这里可以总结为三个核心方法:


resolveMultipleBeans,处理集合类型,如Array、Map、Collection;

findAutowireCandidates,处理单个对象

descriptor.resolveCandidate(autowiredBeanName, type, this);,将Class对象解析为真实的bean实例,这里会触发getBean的过程。可以说真正的依赖解析是在这里实行的。

————————————————

⑤ @Value

在上面方法中可以看到如下代码,其实就是对@Value注解做了处理。

Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);


如下所示,AbstractBeanFactoryresolveEmbeddedValue方法会尝试使用StringValueResolver解析得到实际的Value值,比如本文这里的D://myfilemapping/bookrecommend/file


【2】postProcessProperties


这里指的是InstantiationAwareBeanPostProcessor的postProcessProperties。前面我们提到过,如果resolvedAutowireMode为0,那么是不会执行autowireByName或者autowireByType的逻辑的。此时@Autowired、@Resource注解就由postProcessProperties方法提供实习。


AutowiredAnnotationBeanPostProcessor处理@Autowired,CommonAnnotationBeanPostProcessor处理@Resource。

如下所示是AutowiredAnnotationBeanPostProcessor的postProcessProperties方法,该方法首先获取到需要依赖注入的元素,然后调用注入方法得到实例对象。

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 获取需要依赖注入的元素
  InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
  try {
  // 启动注入过程
    metadata.inject(bean, beanName, pvs);
  }
  catch (BeanCreationException ex) {
    throw ex;
  }
  catch (Throwable ex) {
    throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
  }
  return pvs;
}

① 获取依赖注入的元素

如下所示AutowiredAnnotationBeanPostProcessorfindAutowiringMetadata方法找到那些标注了@Autowired注解的字段和方法,提取出来需要进行依赖解析的元素。

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);
        }
        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<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
  Class<?> targetClass = clazz;
  do {
    final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
    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));
      }
    });
    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);
}


② 依赖注入对象解析

接下来我们再看一下注入过程

// InjectionMetadata#inject
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
  Collection<InjectedElement> checkedElements = this.checkedElements;
  Collection<InjectedElement> 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);
    }
  }
}
// AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
@Override
  protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    Field field = (Field) this.member;
    Object value;
    // 这是缓存机制
    if (this.cached) {
      value = resolvedCachedArgument(beanName, this.cachedFieldValue);
    }
    else {
      DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
      desc.setContainingClass(bean.getClass());
      Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
      Assert.state(beanFactory != null, "No BeanFactory available");
      TypeConverter typeConverter = beanFactory.getTypeConverter();
      try {
      // 这里是核心,解析依赖
        value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
      }
      catch (BeansException ex) {
        throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
      }
      synchronized (this) {
        if (!this.cached) {
          if (value != null || this.required) {
            this.cachedFieldValue = desc;
            // 记录bean与依赖bean的关系
            registerDependentBeans(beanName, autowiredBeanNames);
            if (autowiredBeanNames.size() == 1) {
              String autowiredBeanName = autowiredBeanNames.iterator().next();
              if (beanFactory.containsBean(autowiredBeanName) &&
                  beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
                this.cachedFieldValue = new ShortcutDependencyDescriptor(
                    desc, autowiredBeanName, field.getType());
              }
            }
          }
          else {
            this.cachedFieldValue = null;
          }
          this.cached = true;
        }
      }
    }
    // 如果value不为null,则为filed赋值value
    if (value != null) {
      ReflectionUtils.makeAccessible(field);
      field.set(bean, value);
    }
  }
}


如上代码所示,这里核心逻辑就是 beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);其将会触发依赖解析过程也就是【1】中的第③部分。


③ @Resource

当你controller有@Resource注解时,CommonAnnotationBeanPostProcessor的postProcessProperties方法就会去解析并注入。

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
  InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
  try {
    metadata.inject(bean, beanName, pvs);
  }
  catch (Throwable ex) {
    throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
  }
  return pvs;
}
private InjectionMetadata findResourceMetadata(String beanName, final 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);
  // metadata == null || metadata.targetClass != clazz
  if (InjectionMetadata.needsRefresh(metadata, clazz)) {
  // 加锁--双重校验锁
    synchronized (this.injectionMetadataCache) {
    //再次从缓存获取
      metadata = this.injectionMetadataCache.get(cacheKey);
      // 再次进行判断
      if (InjectionMetadata.needsRefresh(metadata, clazz)) {
        if (metadata != null) {
          metadata.clear(pvs);
        }
        // 核心在这里,根据Bean类型获取其需要处理的@Resource元素
        metadata = buildResourceMetadata(clazz);
        // 放入缓存
        this.injectionMetadataCache.put(cacheKey, metadata);
      }
    }
  }
  return metadata;
}


我们看下其收集元素的方法,这里将会收集目标元素如WebServiceRefElement(@WebServiceRef)EjbRefElement(@EJB)及我们常用的ResourceElement(@Resource)

private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
  if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) {
    return InjectionMetadata.EMPTY;
  }
  List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
  Class<?> targetClass = clazz;
  do {
    final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// 从field字段级别收集
    ReflectionUtils.doWithLocalFields(targetClass, field -> {
      if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
        if (Modifier.isStatic(field.getModifiers())) {
          throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
        }
        currElements.add(new WebServiceRefElement(field, field, null));
      }
      else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
        if (Modifier.isStatic(field.getModifiers())) {
          throw new IllegalStateException("@EJB annotation is not supported on static fields");
        }
        currElements.add(new EjbRefElement(field, field, null));
      }
      else if (field.isAnnotationPresent(Resource.class)) {
        if (Modifier.isStatic(field.getModifiers())) {
          throw new IllegalStateException("@Resource annotation is not supported on static fields");
        }
        if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
          currElements.add(new ResourceElement(field, field, null));
        }
      }
    });
// 从方法级别收集
    ReflectionUtils.doWithLocalMethods(targetClass, method -> {
      Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
      if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
        return;
      }
      if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
        if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
          if (Modifier.isStatic(method.getModifiers())) {
            throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
          }
          if (method.getParameterCount() != 1) {
            throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
          }
          PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
          currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
        }
        else if (ejbRefClass != null && bridgedMethod.isAnnotationPresent(ejbRefClass)) {
          if (Modifier.isStatic(method.getModifiers())) {
            throw new IllegalStateException("@EJB annotation is not supported on static methods");
          }
          if (method.getParameterCount() != 1) {
            throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
          }
          PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
          currElements.add(new EjbRefElement(method, bridgedMethod, pd));
        }
        else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
          if (Modifier.isStatic(method.getModifiers())) {
            throw new IllegalStateException("@Resource annotation is not supported on static methods");
          }
          Class<?>[] paramTypes = method.getParameterTypes();
          if (paramTypes.length != 1) {
            throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
          }
          if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
            PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
            currElements.add(new ResourceElement(method, bridgedMethod, pd));
          }
        }
      }
    });
    elements.addAll(0, currElements);
    targetClass = targetClass.getSuperclass();
  }
  while (targetClass != null && targetClass != Object.class);
  return InjectionMetadata.forElements(elements, clazz);
}


9ca918dab6bf4c03a09004f395781fbb.png


获取到目标元素后(比如我们@Resource注解的对象),其将会通过如下方法调用栈进行依赖的解析。

// 方法调用栈
InjectionMetadata#inject ->
InjectionMetadata.InjectedElement#inject ->
CommonAnnotationBeanPostProcessor.ResourceElement#getResourceToInject ->
CommonAnnotationBeanPostProcessor#getResource ->
CommonAnnotationBeanPostProcessor#autowireResource ->
DefaultListableBeanFactory#resolveDependency


这里我们最后可以看到,其同样走到了DefaultListableBeanFactoryd的resolveDependency方法,不再赘述。


需要注意一点的是,同@Autowired解析依赖的过程一样,这里也实现了lazyLookup 兼容。如果lazyLookup 为true,则创建代理,不触发实际对象解析。

// CommonAnnotationBeanPostProcessor.ResourceElement#getResourceToInject
@Override
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
  return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
      getResource(this, requestingBeanName));
}


目录
相关文章
|
9天前
|
Java Spring
在使用Spring的`@Value`注解注入属性值时,有一些特殊字符需要注意
【10月更文挑战第9天】在使用Spring的`@Value`注解注入属性值时,需注意一些特殊字符的正确处理方法,包括空格、引号、反斜杠、新行、制表符、逗号、大括号、$、百分号及其他特殊字符。通过适当包裹或转义,确保这些字符能被正确解析和注入。
|
21天前
|
Java 测试技术 程序员
为什么Spring不推荐@Autowired用于字段注入?
作为Java程序员,Spring框架在日常开发中使用频繁,其依赖注入机制带来了极大的便利。然而,尽管@Autowired注解简化了依赖注入,Spring官方却不推荐在字段上使用它。本文将探讨字段注入的现状及其存在的问题,如难以进行单元测试、违反单一职责原则及易引发NPE等,并介绍为何Spring推荐构造器注入,包括增强代码可读性和维护性、方便单元测试以及避免NPE等问题。通过示例代码展示如何将字段注入重构为构造器注入,提高代码质量。
|
25天前
|
缓存 Java Spring
源码解读:Spring如何解决构造器注入的循环依赖?
本文详细探讨了Spring框架中的循环依赖问题,包括构造器注入和字段注入两种情况,并重点分析了构造器注入循环依赖的解决方案。文章通过具体示例展示了循环依赖的错误信息及常见场景,提出了三种解决方法:重构代码、使用字段依赖注入以及使用`@Lazy`注解。其中,`@Lazy`注解通过延迟初始化和动态代理机制有效解决了循环依赖问题。作者建议优先使用`@Lazy`注解,并提供了详细的源码解析和调试截图,帮助读者深入理解其实现机制。
19 1
|
25天前
|
设计模式 Java Spring
Spring Boot监听器的底层实现原理
Spring Boot监听器的底层实现原理主要基于观察者模式(也称为发布-订阅模式),这是设计模式中用于实现对象之间一对多依赖的一种常见方式。在Spring Boot中,监听器的实现依赖于Spring框架提供的事件监听机制。
25 1
|
2月前
|
XML Java 开发者
经典面试---spring IOC容器的核心实现原理
作为一名拥有十年研发经验的工程师,对Spring框架尤其是其IOC(Inversion of Control,控制反转)容器的核心实现原理有着深入的理解。
92 3
|
3月前
|
XML Java 数据格式
Spring5入门到实战------4、IOC容器-Bean管理XML方式、集合的注入(二)
这篇文章是Spring5框架的实战教程,主题是IOC容器中Bean的集合属性注入,通过XML配置方式。文章详细讲解了如何在Spring中注入数组、List、Map和Set类型的集合属性,并提供了相应的XML配置示例和Java类定义。此外,还介绍了如何在集合中注入对象类型值,以及如何使用Spring的util命名空间来实现集合的复用。最后,通过测试代码和结果展示了注入效果。
Spring5入门到实战------4、IOC容器-Bean管理XML方式、集合的注入(二)
|
3月前
|
缓存 Java 数据库连接
Spring Boot 资源文件属性配置,紧跟技术热点,为你的应用注入灵动活力!
【8月更文挑战第29天】在Spring Boot开发中,资源文件属性配置至关重要,它让开发者能灵活定制应用行为而不改动代码,极大提升了可维护性和扩展性。Spring Boot支持多种配置文件类型,如`application.properties`和`application.yml`,分别位于项目的resources目录下。`.properties`文件采用键值对形式,而`yml`文件则具有更清晰的层次结构,适合复杂配置。此外,Spring Boot还支持占位符引用和其他外部来源的属性值,便于不同环境下覆盖默认配置。通过合理配置,应用能快速适应各种环境与需求变化。
41 0
|
3月前
|
安全 Java 开发者
开发者必看!@Resource与private final的较量,Spring Boot注入技巧大揭秘,你不可不知的细节!
【8月更文挑战第29天】Spring Boot作为热门Java框架,其依赖注入机制备受关注。本文通过对比@Resource(JSR-250规范)和@Autowired(Spring特有),并结合private final声明的字段注入,详细探讨了两者的区别与应用场景。通过示例代码展示了@Resource按名称注入及@Autowired按类型注入的特点,并分析了它们在注入时机、依赖性、线程安全性和单一职责原则方面的差异,帮助开发者根据具体需求选择最合适的注入策略。
81 0
|
Java Spring
通过Spring Resource接口获取资源(6)
通过Spring Resource接口获取资源
1107 0
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。