IOC 容器中那些鲜为人知的细节(关于 autowiring)

1、博客内容均出自于咕泡学院架构师第三期
2、架构师系列内容:架构师学习笔记(持续更新)

Spring IOC 容器提供了两种管理 Bean 依赖关系的方式:
1)、显式管理:通过 BeanDefinition 的属性值和构造方法实现 Bean 依赖关系管理。
2)、autowiring:Spring IOC 容器的依赖自动装配功能,不需要对 Bean 属性的依赖关系做显式的声明, 只需要在配置好 autowiring 属性,IOC 容器会自动使用反射查找属性的类型和名称,然后基于属性的类型或者名称来自动匹配容器中管理的 Bean,从而自动地完成依赖注入。

通过对 autowiring 自动装配特性的理解,我们知道容器对 Bean 的自动装配发生在容器对 Bean 依赖注入的过程中。在前面对 Spring IOC 容器的依赖注入过程源码分析中,我们已经知道了容器对 Bean 实例对象的属性注入的处理发生在 AbstractAutoWireCapableBeanFactory 类中的 populateBean()方法中,我们通过程序流程分析 autowiring 的实现原理:

1、AbstractAutoWireCapableBeanFactory 对 Bean 实例进行属性依赖注入

应用第一次通过 getBean()方法(配置了 lazy-init 预实例化属性的除外)向 IOC 容器索取 Bean 时,容器创建 Bean 实例对象 , 并 且对 Bean 实例对象进行属性依赖注入 ,AbstractAutoWireCapableBeanFactory 的 populateBean()方法就是实现 Bean 属性依赖注入的功能,其主要源码如下:

//将Bean属性设置到生成的实例对象上
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
   if (bw == null) {
      if (mbd.hasPropertyValues()) {
         throw new BeanCreationException(
               mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
      }
      else {
         // Skip property population phase for null instance.
         return;
      }
   }


   // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
   // state of the bean before properties are set. This can be used, for example,
   // to support styles of field injection.
   boolean continueWithPropertyPopulation = true;


   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
               continueWithPropertyPopulation = false;
               break;
            }
         }
      }
   }


   if (!continueWithPropertyPopulation) {
      return;
   }
   //获取容器在解析Bean定义资源时为BeanDefiniton中设置的属性值
   PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);


   //对依赖注入处理,首先处理autowiring自动装配的依赖注入
   if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
         mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
      MutablePropertyValues newPvs = new MutablePropertyValues(pvs);


      // Add property values based on autowire by name if applicable.
      //根据Bean名称进行autowiring自动装配处理
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
         autowireByName(beanName, mbd, bw, newPvs);
      }


      // Add property values based on autowire by type if applicable.
      //根据Bean类型进行autowiring自动装配处理
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
         autowireByType(beanName, mbd, bw, newPvs);
      }


      pvs = newPvs;
   }


   //对非autowiring的属性进行依赖注入处理


   boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
   boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);


   if (hasInstAwareBpps || needsDepCheck) {
      if (pvs == null) {
         pvs = mbd.getPropertyValues();
      }
      PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      if (hasInstAwareBpps) {
         for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
               InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
               pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
               if (pvs == null) {
                  return;
               }
            }
         }
      }
      if (needsDepCheck) {
         checkDependencies(beanName, mbd, filteredPds, pvs);
      }
   }


   if (pvs != null) {
      //对属性进行注入
      applyPropertyValues(beanName, mbd, bw, pvs);
   }
}

2、Spring IOC 容器根据 Bean 名称或者类型进行 autowiring 自动依赖注入

//根据类型对属性进行自动依赖注入
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对象中非简单属性(不是简单继承的对象,如8中原始类型,字符
   //URL等都是简单属性)进行处理
   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类型的属性进行autowiring自动依赖注入
         if (Object.class != pd.getPropertyType()) {
            //获取属性的setter方法
            MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
            // Do not allow eager init for type matching in case of a prioritized post-processor.
            //检查指定类型是否可以被转换为目标对象的类型
            boolean eager = !PriorityOrdered.class.isInstance(bw.getWrappedInstance());
            //创建一个要被注入的依赖描述
            DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
            //根据容器的Bean定义解析依赖关系,返回所有要被注入的Bean对象
            Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
            if (autowiredArgument != null) {
               //为属性赋值所引用的对象
               pvs.add(propertyName, autowiredArgument);
            }
            for (String autowiredBeanName : autowiredBeanNames) {
               //指定名称属性注册依赖Bean名称,进行属性依赖注入
               registerDependentBean(autowiredBeanName, beanName);
               if (logger.isDebugEnabled()) {
                  logger.debug("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);
      }
   }
}

通过上面的源码分析,我们可以看出来通过属性名进行自动依赖注入的相对比通过属性类型进行自动依赖注入要稍微简单一些 , 但 是 真正实现属性注入的是 DefaultSingletonBeanRegistry 类 的registerDependentBean()方法。

3、DefaultSingletonBeanRegistry 的 registerDependentBean()方法对属性注入

//为指定的Bean注入依赖的Bean
public void registerDependentBean(String beanName, String dependentBeanName) {
   // A quick check for an existing entry upfront, avoiding synchronization...
   //处理Bean名称,将别名转换为规范的Bean名称
   String canonicalName = canonicalName(beanName);
   Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
   if (dependentBeans != null && dependentBeans.contains(dependentBeanName)) {
      return;
   }


   // No entry yet -> fully synchronized manipulation of the dependentBeans Set
   //多线程同步,保证容器内数据的一致性
   //先从容器中:bean名称-->全部依赖Bean名称集合找查找给定名称Bean的依赖Bean
   synchronized (this.dependentBeanMap) {
      //获取给定名称Bean的所有依赖Bean名称
      dependentBeans = this.dependentBeanMap.get(canonicalName);
      if (dependentBeans == null) {
         //为Bean设置依赖Bean信息
         dependentBeans = new LinkedHashSet<>(8);
         this.dependentBeanMap.put(canonicalName, dependentBeans);
      }
      //向容器中:bean名称-->全部依赖Bean名称集合添加Bean的依赖信息
      //即,将Bean所依赖的Bean添加到容器的集合中
      dependentBeans.add(dependentBeanName);
   }
   //从容器中:bean名称-->指定名称Bean的依赖Bean集合找查找给定名称Bean的依赖Bean
   synchronized (this.dependenciesForBeanMap) {
      Set<String> dependenciesForBean = this.dependenciesForBeanMap.get(dependentBeanName);
      if (dependenciesForBean == null) {
         dependenciesForBean = new LinkedHashSet<>(8);
         this.dependenciesForBeanMap.put(dependentBeanName, dependenciesForBean);
      }
      //向容器中:bean名称-->指定Bean的依赖Bean名称集合添加Bean的依赖信息
      //即,将Bean所依赖的Bean添加到容器的集合中
      dependenciesForBean.add(canonicalName);
   }
}

通过对 autowiring 的源码分析,我们可以看出,autowiring 的实现过程:
a、对 Bean 的属性代调用 getBean()方法,完成依赖 Bean 的初始化和依赖注入。
b、将依赖 Bean 的属性引用设置到被依赖的 Bean 属性上。
c、将依赖 Bean 的名称和被依赖 Bean 的名称存储在 IOC 容器的集合中。

Spring IOC 容器的 autowiring 属性自动依赖注入是一个很方便的特性,可以简化开发时的配置,但是凡是都有两面性,自动属性依赖注入也有不足,首先,Bean 的依赖关系在 配置文件中无法很清楚地看出来,对于维护造成一定困难。其次,由于自动依赖注入是 Spring 容器自动执行的,容器是不会智能判断的,如果配置不当,将会带来无法预料的后果,所以自动依赖注入特性在使用时还是综合考虑。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值