首页 > 其他分享 >Spring依赖注入(二) - 注入过程

Spring依赖注入(二) - 注入过程

时间:2023-06-18 23:01:10浏览次数:52  
标签:依赖 Nullable 对象 Spring beanName descriptor null 注入

下面会通过源码的方式去分析Spring中的依赖注入过程。

Spring的注入流程大致如下:

Spring依赖注入(二) - 注入过程_构造器

Spring注入过程

Spring注入主要分为了上面4个步骤:

  1. 1. 第一步主要就是不同注入方式的展现,不同的注入方式对应的入口不同,下面会具体讲解
  2. 2. 第二步主要是对注入对象的包装,比如可以使用OptionalObjectFactoryObjectProvider等对象包装要注入的对象

Spring依赖注入(二) - 注入过程_ide_02

image-20230325112747597

  1. 1. 第三步就是从IOC容器通过注入的类型或者名称找到注入的的对象,当然这个过程可以在IOC中找到多个对象,这时候就需要通过注入对象的类型来组装返回结果,如果是集合类型则都返回,如果是单个对象则返回被@Primary修饰的对象。
  2. 2. 第四步就是将组装好的对象通过反射赋值到需要注入的对象身上

首先说明:阅读源码并不需要关注到每一个方法的功能上,所以下面我只展示出重要的方法

依赖处理过程

在上面注入过程中,第一步存在不同的注入方法,各种注入方法的实现也不尽相同,只有二、三步查找的方法都是统一的,所以在这里我们先来分析第二步第三步的过程。

我们知道,在Spring的默认实现中,不管你是使用ClassPathXmlApplicationContext创建的Spring上下文还是使用AnnotationConfigApplicationContext创建的上下文,其实最终的Spring中的BeanFactory类型都是DefaultListableBeanFactory,所以其实Spring中依赖处理过程的代码也是存在于在DefaultListableBeanFactory对象doResolveDependency方法上面。

处理入口

doResolveDependency方法是AutowireCapableBeanFactory接口中定义的方法,存在两个:

Spring依赖注入(二) - 注入过程_ide_03

image-20230325114925282

而两个参数的重载方法在AbstractAutowireCapableBeanFactory中调用了四个参数的重载方法,所以依赖处理过程都是在四个参数的doResolveDependency中进行的:

@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException {
  // 调用了四个参数的重载方法
  return resolveDependency(descriptor, requestingBeanName, null, null);
}

在四个参数方法中主要有对象参数:DependencyDescriptorTypeConverter

TypeConverter主要用于类型转换,这里我们可以先不看,我们主要看一下DependencyDescriptor对象,DependencyDescriptor主要描述了被注入对象的一些详细信息。他主要包含了以下字段:

public class DependencyDescriptor extends InjectionPoint implements Serializable {
  // 被注入的容器
  private final Class<?> declaringClass;
  // 方法名称 - 方法注入
  @Nullable
  private String methodName;
  // 构造器参数 - 构造器注入
  @Nullable
  private Class<?>[] parameterTypes;
  // 参数索引 - 参数在构造器中的顺序,也就是标注在那个参数来操作
  private int parameterIndex;
  // 字段名称 - 字段注入
  @Nullable
  private String fieldName;
  // 是否必须 - 如对应 @Autowired 注解中的required
  private final boolean required;
  // 是否懒加载 - 如对应 @Lazy 注解标注
  private final boolean eager;
  // 嵌套层次 - 如 @Autowired 标注在嵌套类中
  private int nestingLevel = 1;
  // 包含的类
  @Nullable
  private Class<?> containingClass;
  @Nullable
  private transient volatile ResolvableType resolvableType;
  @Nullable
  private transient volatile TypeDescriptor typeDescriptor;

  // ... 省略其他
}

public class InjectionPoint {
  // 方法参数
  @Nullable
  protected MethodParameter methodParameter;
  // 注入对象类型
  @Nullable
  protected Field field;
  // 字段注解
  @Nullable
  private volatile Annotation[] fieldAnnotations;
}

从中可以看出DependencyDescriptor核心就是描述了如下几个注入对象的特征:

  • • 被注入的容器 - 注入对象所属的外层容器
  • • 注入方式 - 方法注入、构造器注入还是字段注入
  • • 是否可以为空
  • • 是否是懒加载
  • • 注入对象的层级

接下来,我们进入resolveDependency方法一探究竟!

包装注入对象

这个步骤对应的是上面流程中的第二步,主要作用就是判断注入对象是否被OptionalObjectFactoryObjectProvider等对象进行包装,如果被包装过则从包装中取出实际的注入类型进行注入流程。

我们透过代码来看看:

@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);
  }
  // javaxInjectProviderClass在构造器中声明是javax.inject.Provider对象
  else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
    return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
  }
  else {
    // 判断对象是否被@Lazy修饰,是则返回代理对象
    Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
      descriptor, requestingBeanName);
    if (result == null) {
      // 都不是说明本身就是要注入的类型,开始查找并组装对象  最核心
      result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
    }
    return result;
  }
}

上面代码其实非常简单,其实就是不同类型走不同的判断,在上面代码中,其实最核心的就是最后的if中执行的方法doResolveDependency方法,他是DefaultListableBeanFactory自己的一个方法。其实上面的几个判断最终都要走到改方法中去,只是上面会对改方法进行包装或者代理。

查找组装注入对象

从上面我们看的,注入不同的类型走不同的方法,下面我们就不每种方法就点进去讲解了,我们主要看核心方法注入普通一个对象的方式,也就是doResolveDependency方法中执行的内容。

  • • doResolveDependency:
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
                                  @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
  // ...
  Class<?> type = descriptor.getDependencyType();

  // 1、对@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);
      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()));
    }
  }

  // ...
  // 2、判断查找对象的方式是否是数据或集合等多个的形式
  Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
  if (multipleBeans != null) {
    return multipleBeans;
  }

  // 3、重点  依赖查找 beanName:需要被注入到的Bean名称 type:注入的bean类型
  // 返回多个,因为上下文type相同的Bean可能会存在多个 key为bean名称
  Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
  if (matchingBeans.isEmpty()) {
    return null;
  }

  String autowiredBeanName;
  Object instanceCandidate;

  if (matchingBeans.size() > 1) {
    // 4.1、如果是多个Bean的情况下返回被primary标注或者标注为最高优先级的Bean名称
    autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);

    // 取出对应bean名称的class
    instanceCandidate = matchingBeans.get(autowiredBeanName);
  }
  else {
    // 4.2、如果只有一个则直接取出
    Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
    autowiredBeanName = entry.getKey();
    instanceCandidate = entry.getValue();
  }

  if (autowiredBeanNames != null) {
    autowiredBeanNames.add(autowiredBeanName);
  }
  if (instanceCandidate instanceof Class) {
    // 5、从IOC容器中取出对象,实际执行 beanFactory.getBean(beanName);
    instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
  }
  Object result = instanceCandidate;

  // ...

  return result;
}
  • • resolveMultipleBeans: 多对象注入处理

该注入方式代码很清晰,其实也是调用的findAutowireCandidates方法

@Nullable
private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
                                    @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {

  Class<?> type = descriptor.getDependencyType();

  // 1、StreamDependencyDescriptor类型
  if (descriptor instanceof StreamDependencyDescriptor) {
    Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
    if (autowiredBeanNames != null) {
      autowiredBeanNames.addAll(matchingBeans.keySet());
    }
    // ...
    return stream;
  }
  // 2、数组类型
  else if (type.isArray()) {
    // ...
    Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
                                                               new MultiElementDescriptor(descriptor));
    if (matchingBeans.isEmpty()) {
      return null;
    }
    if (autowiredBeanNames != null) {
      autowiredBeanNames.addAll(matchingBeans.keySet());
    }
    // ...
    return result;
  }
  // 3、集合类型
  else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
    // ...
    Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
                                                               new MultiElementDescriptor(descriptor));
    if (matchingBeans.isEmpty()) {
      return null;
    }
    if (autowiredBeanNames != null) {
      autowiredBeanNames.addAll(matchingBeans.keySet());
    }
    // ...
    return result;
  }
  // 4、Map类型
  else if (Map.class == type) {
    // ...
    Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
                                                               new MultiElementDescriptor(descriptor));
    if (matchingBeans.isEmpty()) {
      return null;
    }
    if (autowiredBeanNames != null) {
      autowiredBeanNames.addAll(matchingBeans.keySet());
    }
    return matchingBeans;
  }
  else {
    // 5、都不是返回null
    return null;
  }
}
  • • findAutowireCandidates: 查找依赖注入的核心
protected Map<String, Object> findAutowireCandidates(
  @Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
  // 1、返回当前上下文对象中类型为requiredType的所有bean名称
  String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
    this, requiredType, true, descriptor.isEager());
  Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);

  // 2、resolvableDependencies是未加入容器管理的一种对象,该种对象可以被依赖注入,却不能被getBean()获取(非 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;
      }
    }
  }

  // 3、下面代码都是为了通过名称和类型到上下文中查找到对应的对象并添加到result中
  for (String candidate : candidateNames) {
    if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
      addCandidateEntry(result, candidate, descriptor, requiredType);
    }
  }
  if (result.isEmpty()) {
    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);
      }
    }
    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;
}

依赖注入过程中对象查找的简单过程大致就是上面的流程,其中核心的第三步涉及一个注入来源查找,从代码我们也可以简单分析出,在注入过程的查找来源主要有三个部分:

  • • @Value的外部化配置;
  • • 被Spring容器管理的对象;
  • • 没有被Spring容器管理的ResolvableDependencies中的对象。

具体的注入查找来源的具体在后面进行讲解。

筛选注入字段

上面我们讲完了注入对象查找的具体方式和过程,接下来我们回到第一步和第四部,我们看看在@Autowired@Resource分别是在那些对象中进行查找和处理需要注入的对象的。

原生注解

Spring原生注解注入主要指的就是@Autowired,当然也不止只有他,下面会详情说,Spring原生注解注入主要是在AutowiredAnnotationBeanPostProcessor对象中进行处理的,当然,我们也不是一定必须是使用Autowired注入,因为在AutowiredAnnotationBeanPostProcessor提供了一个setAutowiredAnnotationType的方法来进行筛选注解设置。

构造方法:

首先我们看AutowiredAnnotationBeanPostProcessor对象的构造方法

public AutowiredAnnotationBeanPostProcessor() {
  // autowiredAnnotationTypes是个List,存在顺序
  this.autowiredAnnotationTypes.add(Autowired.class);
  this.autowiredAnnotationTypes.add(Value.class);
  try {
    this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
                                      ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
    logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
  }
  catch (ClassNotFoundException ex) {
    // JSR-330 API not available - simply skip.
  }
}

AutowiredAnnotationBeanPostProcessor主要处理三个注解:

  1. 1. @Autowired
  2. 2. @Value
  3. 3. JSR330中的javax.inject.Inject注解

其中在findAutowiredAnnotation中描述了三个注解同时出现时会优先使用的方式:

@Nullable
private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
  MergedAnnotations annotations = MergedAnnotations.from(ao);
  // 添加顺序就是实际顺序,所以三个注解同时存在时候会以Autowired为主
  for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
    MergedAnnotation<?> annotation = annotations.get(type);
    if (annotation.isPresent()) {
      return annotation;
    }
  }
  return null;
}

言归正传,我们回到注入处理流程,在AutowiredAnnotationBeanPostProcessor中有个方法叫postProcessProperties,他是一个对象注入的开始位置:

  • • 1、AutowiredAnnotationBeanPostProcessor#postProcessProperties():

主要作用:筛选出目标对象的字段中被Autowired标注为需要注入的所有字段

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
  // 里面执行了findAutowiredAnnotation方法,返回目标对象及其目标对象中被Autowired标注的所有属性等信息
  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;
}
  • • 2、InjectionMetadata#inject():

主要作用是遍历需要注入的所有字段并对其一一注入。

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
  Collection<InjectedElement> checkedElements = this.checkedElements;
  // 返回被Autowired标注的所有需要注入的字段
  Collection<InjectedElement> elementsToIterate =
    (checkedElements != null ? checkedElements : this.injectedElements);
  if (!elementsToIterate.isEmpty()) {
    // 遍历需要注入的字段一一进行注入
    for (InjectedElement element : elementsToIterate) {
      element.inject(target, beanName, pvs);
    }
  }
}
  • • 3、AutowiredFieldElement#inject()

在IOC容器中筛选出符合条件的对象,并赋值到目标对象中,也就是在此步骤中会执行依赖处理过程的resolveDependency()方法。

当然,下面列出主要是字段注入的情况,还有另外一种方法注入主要InjectedElement实现类不同而已,但是最终都是到resolveDependency找注入对象,下面我们就只拿属性注入来看。

@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
  // 获得需要注入的字段
  Field field = (Field) this.member;
  Object value;
  if (this.cached) {
    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 {
    // 里面执行了依赖处理过程中的resolveDependency方法
    value = resolveFieldValue(field, bean, beanName);
  }
  if (value != null) {
    // 反射赋值
    ReflectionUtils.makeAccessible(field);
    field.set(bean, value);
  }
}

通用注解

什么是通用注解注入?

通用注解注入主要是指处理一些Java规范中一些如@Resource@PostConstruct@PreDestroy注解的注入。

通用注解的入口是CommonAnnotationBeanPostProcessor,首先我们也来看一下构造方法,了解他主要处理的注解:

public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
  implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {

  static {
    webServiceRefClass = loadAnnotationType("javax.xml.ws.WebServiceRef");
    ejbClass = loadAnnotationType("javax.ejb.EJB");

    resourceAnnotationTypes.add(Resource.class);
    if (webServiceRefClass != null) {
      resourceAnnotationTypes.add(webServiceRefClass);
    }
    if (ejbClass != null) {
      resourceAnnotationTypes.add(ejbClass);
    }
  }

  public CommonAnnotationBeanPostProcessor() {
    setOrder(Ordered.LOWEST_PRECEDENCE - 3);
    setInitAnnotationType(PostConstruct.class);
    setDestroyAnnotationType(PreDestroy.class);
    ignoreResourceType("javax.xml.ws.WebServiceContext");
  }
}

从中我们也可以看出,CommonAnnotationBeanPostProcessor主要处理注入的三个注解:

  1. 1. @Resource
  2. 2. 注解javax.xml.ws.WebServiceRef
  3. 3. 注解javax.ejb.EJB

以及生命周期的两个注解:

  1. 1. @PostConstruct
  2. 2. @PreDestroy

但是与AutowiredAnnotationBeanPostProcessor不同的是,在校验注解存在时在CommonAnnotationBeanPostProcessor中是采用包含的方式校验的:

// 校验clazz是否在resourceAnnotationTypes中包含
AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)

CommonAnnotationBeanPostProcessor的处理过程思想和逻辑都和AutowiredAnnotationBeanPostProcessor有很多相同之处,有一点点区别在功能上我们也能知道。那就是注入的顺序:

  • • @Autowired 先根据类型(byType)查找,如果存在多个(Bean)再根据名称(byName)进行查找;
  • • @Resource 先根据名称(byName)查找,如果(根据名称)查找不到,再根据类型(byType)进行查找。

而这个存在的区别主要就存在于InjectedElement对象的实现类上,AutowiredAnnotationBeanPostProcessor中对InjectedElement使用的实现类是AutowiredFieldElement(用于字段注入)和AutowiredMethodElement(用于方法注入),而CommonAnnotationBeanPostProcessor使用的是InjectedElement(里面既包含了字段注入,也包含了方法注入)

CommonAnnotationBeanPostProcessor对象中注入的前两步和AutowiredAnnotationBeanPostProcessor几乎一摸一样,这里我们主要看一下InjectedElement及其之后的逻辑。

  • • InjectedElement#inject()

字段注入和方法注入放在一起,而且都是走的getResourceToInject获得注入对象的值。

protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
  throws Throwable {
  // 是否是字段
  if (this.isField) {
    Field field = (Field) this.member;
    ReflectionUtils.makeAccessible(field);
    field.set(target, getResourceToInject(target, requestingBeanName));
  }
  else {
    if (checkPropertySkipping(pvs)) {
      return;
    }
    try {
      // 方法注入
      Method method = (Method) this.member;
      ReflectionUtils.makeAccessible(method);
      method.invoke(target, getResourceToInject(target, requestingBeanName));
    }
    catch (InvocationTargetException ex) {
      throw ex.getTargetException();
    }
  }
}
  • • InjectionMetadata.InjectedElement#getResourceToInject()

ResourceElementInjectionMetadata.InjectedElement对象的一个子类,他针对于不同外部注入的方式有不同的现实。

Spring依赖注入(二) - 注入过程_构造器_04

image-20230326120430926

我们还是主要拿Resource的实现来讲:

@Override
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
  // 校验注入方式是否是实时注入
  return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
          getResource(this, requestingBeanName));
}

接下来我们还是以实施注入的代码来讲

  • • CommonAnnotationBeanPostProcessor#getResource()
protected Object getResource(LookupElement element, @Nullable String requestingBeanName)
  throws NoSuchBeanDefinitionException {
  // ...
 
  return autowireResource(this.resourceFactory, element, requestingBeanName);
}
  • • CommonAnnotationBeanPostProcessor#autowireResource()

下面就是@Resource区别于Autowired注入方式的地方

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

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

  // factory类型判断是否是AutowireCapableBeanFactory类型的对象
  if (factory instanceof AutowireCapableBeanFactory) {
    AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;
    DependencyDescriptor descriptor = element.getDependencyDescriptor();
    // !factory.containsBean(name) 通过名称到Spring IOC容器中查找是否存在对应的对象
    if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
      autowiredBeanNames = new LinkedHashSet<>();
      // 如果Spring IOC中不存在使用resolveDependency走依赖查找处理过程
      resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
      if (resource == null) {
        throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
      }
    }
    else {
      // 说明IOC容器中存在对应的对象,则直接从IOC中取
      resource = beanFactory.resolveBeanByName(name, descriptor);
      autowiredBeanNames = Collections.singleton(name);
    }
  }
  else {
    // 直接从IOC中取
    resource = factory.getBean(name, element.lookupType);
    autowiredBeanNames = Collections.singleton(name);
  }
  // ...

  return resource;
}


标签:依赖,Nullable,对象,Spring,beanName,descriptor,null,注入
From: https://blog.51cto.com/u_16115561/6509953

相关文章

  • apt安装软件时发生依赖破坏
    现象:root@kali:~#apt-getinstallfcitx正在读取软件包列表...完成正在分析软件包的依赖关系树正在读取状态信息...完成有一些软件包无法被安装。如果您用的是unstable发行版,这也许是因为系统无法达到您要求的状态造成的。该版本中可能会有一些您需要的软件包尚......
  • SpringMVC
    1、什么是MVCMVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分M:Model,模型层,指工程中的JavaBean,作用是处理数据JavaBean分为两类:一类称为实体类Bean:专门存储业务数据的,如Student、User等一类称为业务处理Bean:指Service或Dao对象,专门用于处理业务逻辑和......
  • SpringMVC笔记
    一、SpringMVC简介1、什么是MVC2、什么是SpringMVC3、SpringMVC的特点二、HelloWorld1、开发环境2、创建maven工程a>添加web模块b>打包方式:warc>引入依赖3、配置web.xmla>默认配置方式b>扩展配置方式4、创建请求控制器5、创建springMVC的配置文件6、测试HelloWorlda>实现对首页的......
  • SpringCloud学习(二)
    参考:https://blog.csdn.net/qq_25928447/article/details/123899694?spm=1001.2014.3001.5502前面了解了微服务的一套解决方案,但是它是基于Netflix的解决方案,实际上的很多框架都已经停止维护了注册中心:Eureka(属于Netflix,2.x版本不再开源,1.x版本仍在更新)服务调用:Ribbon(......
  • springboot第26集:centos,docker
    yum-vLoading"fastestmirror"pluginLoading"langpacks"pluginLoading"product-id"pluginLoading"search-disabled-repos"pluginLoading"subscription-manager"pluginAddingen\_US.UTF-8tolanguageli......
  • Spring Security6 全新写法,大变样!
    文章目录1.WebSecurityConfigurerAdapter2.使用Lambda3.自定义JSON登录3.1自定义JSON登录3.1.1自定义登录过滤器3.1.2自定义登录接口3.2原因分析3.3问题解决SpringSecurity在最近几个版本中配置的写法都有一些变化,很多常见的方法都废弃了,并且将在未来的SpringS......
  • SpringMVC — 控制器
    SpringMVC—控制器创建一个Controller控制器:使用@Controller对类进行注解,将被标注的类设置为一个控制器使用@RequestMapping对类或方法进行注解,用来映射一个请求和请求的方法。属性value指请求的urlmethod可指明RequestMethod.POST即表单必须要是method=”po......
  • springboot中操作redis
    1.maven引入相关依赖<dependencies> <!--spring-boot-starter-data-redis--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId&g......
  • SpringMVC —— 前提
    SpringMVC—前提前提了解:Web开发中的一些概念JavaBean规范必须是一个公共类,如:publicclassUser{}必须有一个空的构造器类的成员变量是私有,如:privateintid;通过getter/setter来访问属性在软件体系架构中,分层式结构最常见,微软推荐的分层式结构为三层:数据访......
  • SpringBoot:SpringWeb项目+Vue项目dist包整合成jar包
    接到需求做一个小功能项目,其中还要配备前端页面,并且将前端打包进后端jar包内,由jar包运行。项目结构将Vue打包之后的dist文件放到resouces资源路径下修改pom文件将下面的build配置替换掉pom中的build<build><finalName>自定义项目jar名称(可以用${project.artifatId})</finalNam......