<返回更多

Spring的注入模型

2022-06-08    程序员阿龙
加入收藏

一、如何手动设置注入模型

Spring的注入模型属于beanDefifinition的一个属性(默认为0),可以手动设置

xml设置

<bean id="n" class="xxxx" autowire="byType"> </bean>

 

JAVA代码设置

public class ModelBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) beanFactory.getBeanDefinition("bean"); //获取注入模型 
        //手动设置注入模型 
        beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
    }
}

二、Spring的四种注入模型

public interface AutowireCapableBeanFactory extends BeanFactory {

	/**
	 * Constant that indicates no externally defined autowiring. Note that
	 * BeanFactoryAware etc and annotation-driven injection will still be Applied.
	 * @see #createBean
	 * @see #autowire
	 * @see #autowireBeanProperties
	 */
    /**
     * 默认的装配模式,如果注入indexBean,没有在属性上加@Autowired或者@Resource,这时候,indexBean是无法注入的
     */
	int AUTOWIRE_NO = 0;

	/**
	 * Constant that indicates autowiring bean properties by name
	 * (applying to all bean property setters).
	 * @see #createBean
	 * @see #autowire
	 * @see #autowireBeanProperties
	 */
    /**
     * 通过属性名自动装配。Spring寻找与需要自动连接的属性同名的bean。
     * 例如,如果一个bean定义按名称设置为自动装配,并且它包含一个master属性(也就是说,它有一个setMaster(…)方法),
     * Spring就会查找一个名为master的bean定义,并使用它来设置属性。
     */
	int AUTOWIRE_BY_NAME = 1;

	/**
	 * Constant that indicates autowiring bean properties by type
	 * (applying to all bean property setters).
	 * @see #createBean
	 * @see #autowire
	 * @see #autowireBeanProperties
	 */
    /**
     * 如果容器中恰好存在该属性类型的一个bean,则自动连接该属性。
     * 如果存在多个,将抛出一个致命异常,这表明您不能对该bean使用byType自动装配。
     * 如果没有匹配的bean,则什么也不会发生(属性没有设置)。
     */
	int AUTOWIRE_BY_TYPE = 2;

	/**
	 * Constant that indicates autowiring the greediest constructor that
	 * can be satisfied (involves resolving the appropriate constructor).
	 * @see #createBean
	 * @see #autowire
	 */
    /**
     * 类似于byType,但适用于构造函数参数。
     * 如果容器中没有确切的构造函数参数类型的bean,则会引发致命错误。
     */
	int AUTOWIRE_CONSTRUCTOR = 3;

	/**
	 * Constant that indicates determining an appropriate autowire strategy
	 * through introspection of the bean class.
	 * @see #createBean
	 * @see #autowire
	 * @deprecated as of Spring 3.0: If you are using mixed autowiring strategies,
	 * prefer annotation-based autowiring for clearer demarcation of autowiring needs.
	 */
    /**
     * 通过bean的内省来选择合适的自动装配策略(根据英文翻译,就是spring会选择最适合装备的策略)
     */
	@Deprecated
	int AUTOWIRE_AUTODETECT = 4;
  
}

三、Autowired注解注入源码分析

注:此处只分析注入的核心流程,细节不在此展开

通过
AutowiredAnnotationBeanPostProcessor的postProcessProperties方法完成对@Autowired注解的处理和解析

Spring的注入模型

 


Spring的注入模型

 

这里最终会将所有打了Autowiring注解的字段和方法全部构建成
InjectionMetadata.InjectedElement放入一个set集合中进行处理

private InjectionMetadata buildAutowiringMetadata(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 -> {
          
          // 查询是否有 Autowired 注解
         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;
            }
            
            // 判断注解中是否有 Required
            boolean required = determineRequiredStatus(ann);

            // 封装成 AutowiredFieldElement 放入 currElements 集合
            currElements.add(new AutowiredFieldElement(field, required));
         }
      });

           /**
            * 遍历类中所有方法
            */
      ReflectionUtils.doWithLocalMethods(targetClass, method -> {
         Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
         if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
            return;
         }
         
               // 查询是否有 Autowired 注解
         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);
               }
            }
            
                   // 判断注解中是否有 Required
            boolean required = determineRequiredStatus(ann);
            PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
            
                   // 封装成 AutowiredMethodElement 放入 currElements 集合
            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);
}

之后在调用
org.springframework.beans.factory.annotation.InjectionMetadata#inject方法进行属性填充

Spring的注入模型

 

其中
AutowiredAnnotationBeanPostProcessor类里面有3个内部类,其中2个类为AutowiredFieldElement和AutowiredMethodElement,这2个类封装了对打在字段上或者方法上的@Autowired注解进行处理的逻辑;

Spring的注入模型

 

我们就根据AutowiredFieldElement字段上的@Autowired注解进行分析,这个也是我们最常用的方式;

入口方法为inject方法,就是上面InjectionMetadata遍历调用的inject方法;

Spring的注入模型

 


Spring的注入模型

 

org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency

Spring的注入模型

 

org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency

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

      // 获取依赖的类型
      Class<?> type = descriptor.getDependencyType();
      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()));
         }
      }

      /**
            * 解析当前依赖是否支持多个bean注入,如:list、set、map类型等
            * 如果支持多个bean注入,则在内部就完成bean的查找,不为空直接返回
            */
      Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
      if (multipleBeans != null) {
         return multipleBeans;
      }

           /**
            * 根据类型查询bean实例,可能会有多个,key为需要注入对象的名字
            */
      Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
      if (matchingBeans.isEmpty()) {
          // 判断在依赖上面是否加了必须的条件,默认为true
         if (isRequired(descriptor)) {
             // 抛出异常
            raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
         }
         // 如果非必须则返回null,不注入任何对象
         return null;
      }

      String autowiredBeanName;
      Object instanceCandidate;

      // 如果找出的实例大于1个
      if (matchingBeans.size() > 1) {

               // 通过依赖描述组件来推断需要注入对象的名字
         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.
               // 如果找出来的实例为1个,则直接获取出来,赋值给instanceCandidate
         Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
         autowiredBeanName = entry.getKey();
         instanceCandidate = entry.getValue();
      }

      if (autowiredBeanNames != null) {
         autowiredBeanNames.add(autowiredBeanName);
      }
      // 判断是否为Class,如果是则说明没有实例化
      if (instanceCandidate instanceof Class) {
          // 实例化
         instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
      }
      // 将获取到的实例候选赋值给result
      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);
   }
}

四、Autowired分析总结

先根据类型查找bean;如果没有找到则报错(默认情况下@Autowired是一定需要注入一个bean的);如果查找到一个则用找到的这一个完成注入;如果查找到多个,先把这个多个放到map当中,继而根据属性的名字从map当中去获取;能获取到则使用获取的这个;如果map当中通过名字还是无法获取则报错;

@Autowired不会改变bean的注入模型(默认情况下bean的注入模型还是0);@Autowired算是一种半自动注入;因为他只需要程序员告诉spring需要注入的属性或者方法,而不需要程序员告诉spring需要注入的属性或者方法他的值到底是哪个bean;@Autowired会根据自己的规则去查找这个bean,所以只能算作半自动注入;

五、Resource注解注入源码分析

通过
CommonAnnotationBeanPostProcessor这个类的postProcessorProperties方

法来完成对@Resource注解的解析和处理

Spring的注入模型

 

后续的流程和Autowired差不多,就是扫描出来类所有加了Resource注解的属性,封装成对应的
InjectionMetadata.InjectedElement

Spring的注入模型

 


Spring的注入模型

 

在封装成ResourceElement时会读取注解中的值进行参数的赋值

Spring的注入模型

 

在调用ResourceElement的inject方法进行属性注入,但我们发现ResourceElement没有inject方法,我们就可以猜想出,这个方法肯定继承至父类

Spring的注入模型

 

我们最终在
InjectionMetadata.InjectedElement中找到了inject方法

Spring的注入模型

 

在调用子类ResourceElement的getResourceToInject方法

Spring的注入模型

 


Spring的注入模型

 

判断Resource是否自定义了名字,如果自定义了,则不会走类型查询并注入,而是会走else因为自定义了名字说明我们想根据名字注入对象;

如果没有自定义会先根据名字判断是否在单例池中存在或者在beanDefinitionMap中存在,存在则通过名字获取,没有则在通过类型去获取,获取到一个则进行注入,没有获取到或者获取到多个则抛异常;

Spring的注入模型

 


Spring的注入模型

 

六、Resource分析总结

 

@Resource在没有配置name的情况下首先根据名字查找;

如果名字能查找到则返回这个查找到的(spring容器的原则是name唯一的,所以不存在通过名字能查找到多个的情况);

如果通过名字查找不到(需要注意的是这里的前提是没有配置name的情况,spring觉得名字无所谓);因为对名字无要求,所以会再根据类型查找;那么走的就是@Autowired这一套;

如果配置了名字,spring觉得对名字有严格要求,所以只能根据你配置的名字查找;如果查找不到则报错,找到了则用;

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>