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的依赖Beansynchronized (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的依赖Beansynchronized (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 容器自动执行的,容器是不会智能判断的,如果配置不当,将会带来无法预料的后果,所以自动依赖注入特性在使用时还是综合考虑。

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

  1. IOC 容器中那些鲜为人知的细节(关于 FactoryBean 和 BeanFactory)

    1.博客内容均出自于咕泡学院架构师第三期 2.架构师系列内容:架构师学习笔记(持续更新) 在 Spring 中,有两个很容易混淆的类:BeanFactory 和 FactoryBean. BeanFa ...

  2. IOC 容器中那些鲜为人知的细节

    通过前面章节中对Spring IOC 容器的源码分析,我们已经基本上了解了Spring IOC 容器对Bean 定义资源的定位.载入和注册过程,同时也清楚了当用户通过getBean()方法向IOC 容 ...

  3. IOC 容器中那些鲜为人知的细节(关于 延时加载)

    1.博客内容均出自于咕泡学院架构师第三期 2.架构师系列内容:架构师学习笔记(持续更新)) 通过前面我们对 IOC 容器的实现和工作原理分析,我们已经知道 IOC 容器的初始化过程就是对 Bean定义 ...

  4. java 从一个容器获取对象,如何从 Spring IoC 容器中获取对象?

    前面几篇文章主要分析了 Spring IoC 容器如何初始化,以及解析和注册我们定义的 bean 信息. 其中,「Spring 中的 IoC 容器」对 Spring 中的容器做了一个概述,「Sprin ...

  5. IOC容器中bean的生命周期,iocbean生命周期

    原文地址:http://www.bkjia.com/Javabc/1149957.html IOC容器中bean的生命周期,iocbean生命周期 一.Bean的生命周期 Spring IOC容器可以 ...

  6. IOC容器中bean的生命周期

    一.Bean的生命周期 Spring IOC容器可以管理Bean的生命周期,允许在Bean生命周期的特定点执行定制的任务. Spring IOC容器对Bean的生命周期进行管理的过程如下: (1).通 ...

  7. 头条一面:Spring IOC容器中只存放单例Bean吗?

    最近,很多小伙伴出去面试,感觉自己面的不是很理想,回来后,不少小伙伴把面试题做了记录发给我,让我给大家解析下,然后发出来.当我看到这些面试题时,快速在脑海中构建起了整个知识体系,从基础到框架.从分布式 ...

  8. Spring5 - 向IOC容器中添加组件的4种方式

    文章目录 概述 方式一: @CompentScan 适用场景 Code 方式二: @Bean 适用场景 Code 方式三: @Import 适用场景 Code Demo1 Code Demo2 + 实 ...

  9. 六、spring之通过FactoryBean为ioc容器中添加组件

    前面我们已经介绍了几种为容器中添加组件的方法,今天一起学习通过FactoryBean添加组件的方法. 首先我们准备一个类,也就是我们需要注册进spring的ioc容器中的类 类Color: // 不必 ...

最新文章

  1. for循环嵌套 简单优化
  2. 全球及中国低温纳米定位器行业发展趋势分析与风险评估报告2021-2027年版
  3. C语言函数中的参数有const的问题
  4. C语言面向对象编程(二):继承详解
  5. React 学习笔记 —— Ref Hook
  6. 二、搭建Apache服务器 模板引擎
  7. 这篇 Linux 总结得很棒啊!
  8. oracle 查看数据库性能,oracle 11G使用statspack查看数据库的性能
  9. iPhone开发-输出口和操作(转)
  10. 计算机类和数学与应用数学哪个好,数学与应用数学专业怎么样 好不好找工作...
  11. mysql innodb 缓存设置_数据库分享一: MySQL的Innodb缓存相关优化
  12. 面向对象设计必须学习的三层应用程序模型
  13. Ubuntu-10.04中设置和修改root密码
  14. PCB画板与硬件调试+AD快捷键小技巧
  15. 不敢相信!那些真实存在的机器人女友们!
  16. matlab中unifrnd函数用法,概率和统计的MATLAB指令
  17. 第二十八课:focusin与focusout,submit,oninput事件的修复
  18. 怎么给php加音乐,视频中添加背景音乐 怎么给视频添加背景 给视频中某段加背景音乐...
  19. 新高考改革选计算机专业要学什么,2020高考什么专业就业前景好
  20. 想问一下:“哟哟切克闹”是什么意思啊?!哪里出来的?

热门文章

  1. html5经纬度定位 源码_HTML5教程 如何获取当前位置的经纬度
  2. lua面向对象是怎么实现的
  3. 单反相机的常用的几个参数之间的关系
  4. jsp或java中前后台传值乱码解决
  5. 如何用WebIDE打开并运行CRM Fiori应用 1
  6. Promise/A+规范
  7. 除了加强风控,大数据还能为FinTech做些什么?
  8. 在CentOS7上实现NFS共享
  9. JS判断页面是否出现滚动条
  10. 仍有很多企业并未修复微软 Hyber-V 的严重漏洞