大家好,上篇博客我较详细分析了实例化过程,今天继续探讨实例化之后的其它步骤,分别是“填充Bean属性”,“初始化Bean”,“登记善后处理”,“注册单例Bean”,加之实例化,这五个步骤是Spring创建对象的一个完整过程。

一. 填充Bean属性

<bean id="zoo" class="Zoo"><property name="zooName" value="zooName" /><property name="cat" ref="cat" />
</bean><bean id="cat" class="Cat"></bean>

在已获取到对象实例的基础上,这个阶段的任务就是为Bean的属性赋值,比如上图的定义,需要为zoo对象的两个属性“zooName”和“cat”赋值。具体的步骤如下,

1). 首先通过RootBeanDefinition对象的MutablePropertyValues getPropertyValues()方法,获取待赋值给bean属性的属性值集合对象。

2). 然后给予实例化敏感bean后处理器(InstantiationAwareBeanPostProcessor)有机会修改bean实例,调用boolean postProcessAfterInstantiation(Object bean, String beanName)方法对bean实例执行后处理。PS:在Spring启动阶段已经完成了对所有bean后处理的创建和注册,这块内容后续博客会分析。

3). 处理自动装配,前提是用户配置了自动装配策略(BY Name or By Type),默认是禁止自动装配的,并且自动装配也不支持基本类型(诸如Integer、String等)。所谓自动装配就是不需要显式为属性指定值,Spring自动根据属性名称或属性类型,找寻恰当的bean对象为其赋值。经过这个步骤,待赋值给bean属性的属性值变多了。

4). 再次调用实例化敏感bean后处理器,使其有机会在把属性值赋值给bean属性之前,再次执行后处理。这次调用的是后处理器的

PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)

方法,从第一个方法参数可以看出,本次后处理主要是针对待赋值给bean属性的属性值的。

5). 对属性值执行解析, 可以参考上篇博客的这段论述。

6). 把属性值赋值给bean对象。
通过Bean包装器实现该能功能,在Spring内部对bean属性的存取都是通过BeanWrapper实现的,具体可以参看这篇博客。 《Spring3.1.0实现原理分析(四).属性访问器(PropertyAccessor)》

BeanWrapper.setPropertyValues(MutablePropertyValues);

二. 初始化Bean

1). 判断bean对象是否实现了Aware相关接口。

a. 如果bean对象实现了BeanNameAware接口,则调用bean对象的setBeanName(String)方法,意味这bean对象可以获取自身的Id。
b. 如果bean对象实现了BeanClassLoaderAware接口,则调用其setBeanClassLoader方法,bean对象可以获取bean工厂的类加载器。
c. 如果bean对象实现了BeanFactoryAware接口,则调用其setBeanFactory(bf)方法,bean对象可以获取bean工厂。

2). 调用所有bean后处理器的如下方法,在初始化之前对bean执行后处理。

  Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

3). 初始化bean
         如果bean实现了InitializingBean接口,则先调用该接口的void afterPropertiesSet() 方法。其次,如果用户配置bean时指定了init-method="..."属性值,则调用该方法对bean执行初始化操作。

4). 再次调用所有bean后处理器的如下方法,在初始化之后对bean执行后处理。

Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

三. 登记善后处理 (仅适用于单例bean)

登记善后处理需要同时满足两个条件,分别是:

  • bean的生命周期是单例。
  • bean实现了可销毁接口(DisposableBean) 或者 配置了销毁方法(destroy-method="...") 或者 容器中存在销毁敏感bean后处理器(DestructionAwareBeanPostProcessor)。

如果以上两个条件满足,那么Spring会为对bean对象创建一个DisposableBeanAdapter对象,这个对象主要持有以下几点信息,

  • bean对象是否实现了可销毁接口(DisposableBean) 。
  • 如果bean配置了销毁方法(destroy-method="..."),则获取销毁方法名称及方法对象。
  • 从当前容器的bean后处理器集合中,过滤出所有销毁敏感bean后处理器(DestructionAwareBeanPostProcessor),作为列表赋值给成员变量。

被创建的DisposableBeanAdapter对象,会被存储到DefaultSingletonBeanRegistry类的成员变量Map<String, Object> disposableBeans中,其中key是bean's Id。当Spring容器被关闭时(即ConfigurableApplicationContext#close()方法被调用),会调用存储在disposableBeans中的所有DisposableBeanAdapter对象的destroy()方法,执行善后处理,具体执行顺序如下,

  • 调用销毁敏感bean后处理器的void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;方法。
  • 调用DisposableBean接口的destroy()方法。
  • 调用用户配置的销毁方法。

补充:对于web应用ConfigurableApplicationContext#close()方法是在ContextLoaderListener监听器中被自动触发的,但是对于桌面应用,如果希望“善后处理”得到执行需要手动调用ConfigurableApplicationContext#registerShutdownHook()方法,当java虚拟机被关闭时,会回调注册的方法。

四. 注册单例Bean(仅适用于单例bean)

  • 单例bean对象置入DefaultSingletonBeanRegistry类的成员变量singletonObjects 。
  • 把单例bean对象的Id置入DefaultSingletonBeanRegistry类的成员变量registeredSingletons。
/** * 单例对象缓存(key:bean名称;value:单例bean对象) */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>();/*** 已注册的单例bean名称集合*/
private final Set<String> registeredSingletons = new LinkedHashSet<String>(16);

Spring3.1.0实现原理分析(七).填充Bean属性,初始化Bean,登记善后处理,注册单例Bean相关推荐

  1. Spring3.1.0实现原理分析(七).填充Bean属性,初始化Bean,登记善后处理,注册单例Bean...

    大家好,上篇博客我较详细分析了实例化过程,今天继续探讨实例化之后的其它步骤,分别是"填充Bean属性","初始化Bean","登记善后处理" ...

  2. Spring IOC 容器源码分析 - 创建单例 bean 的过程

    1. 简介 在上一篇文章中,我比较详细的分析了获取 bean 的方法,也就是getBean(String)的实现逻辑.对于已实例化好的单例 bean,getBean(String) 方法并不会再一次去 ...

  3. Spring IOC 容器源码分析 - 获取单例 bean

    1. 简介 为了写 Spring IOC 容器源码分析系列的文章,我特地写了一篇 Spring IOC 容器的导读文章.在导读一文中,我介绍了 Spring 的一些特性以及阅读 Spring 源码的一 ...

  4. Android10.0 ContentProvider原理分析

    原文地址:https://skytoby.github.io/2019/ContentProvider%E5%8E%9F%E7%90%86%E5%88%86%E6%9E%90/ 基于Android10 ...

  5. Android 6.0 JNI原理分析 和 Linux系统调用(syscall)原理

    JNI原理 引言:分析Android源码6.0的过程,一定离不开Java与C/C++代码直接的来回跳转,那么就很有必要掌握JNI,这是链接Java层和Native层的桥梁,本文涉及相关源码: fram ...

  6. Alian解读SpringBoot 2.6.0 源码(七):启动流程分析之准备应用上下文

    目录 一.背景 1.1.run方法整体流程 1.2.本文解读范围 二.准备应用上下文 2.1.整体流程 2.2.设置环境 2.3.应用上下文进行后置处理 2.4.应用所有初始化器 2.5.发布应用上下 ...

  7. Spring IOC核心原理分析

    学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的,本文系统分 ...

  8. Java并发编程学习 + 原理分析(建议收藏)

    总结不易,如果对你有帮助,请点赞关注支持一下 微信搜索程序dunk,关注公众号,获取博客源码 Doug Lea是一个无私的人,他深知分享知识和分享苹果是不一样的,苹果会越分越少,而自己的知识并不会因为 ...

  9. 高通Quick Charge快速充电原理分析

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/zoosenpin/article/details/29799709 1 QC2.0 1.1 高通Qu ...

最新文章

  1. 【教程】Python数据可视化技巧
  2. 在线作图|两分钟在线做中性群落模型分析
  3. Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC
  4. Win2008 R2 WEB 服务器设置之禁用不必要的服务和关闭端口
  5. CentOS最小化系统,怎么安装图形界面
  6. 基于matlab的霍夫变换,基于matlab的霍夫变换
  7. OpenCV自动跟踪移动目标DaSiamRPN的实例(附完整代码)
  8. Nginx中break和last的区别
  9. parse data from Nacos error
  10. 计算机设备显示黄色感叹号,电脑没声音,设备管理器中声音出现黄色感叹号怎么办?...
  11. php 微商城 开源,RF 微商城一款免费开源的基础销售功能的微商城正式发布
  12. js 弹窗中写html代码,简单了解JavaScript弹窗实现代码
  13. dw常用标签_DW代码大全
  14. 服务器虚拟化怎么配置,教你如何配置服务器虚拟化环境
  15. 海马玩模拟器连接AndroidStudio
  16. Android call requires API level 12 的解决方案
  17. 【树莓派】树莓派系统安装
  18. 成都大数据语言培训:如何提高数据分析能力
  19. Bonobo Git Server 后台服务安装 详细教程
  20. 数字图像处理学习笔记之一 DIP绪论与MATLAB基础

热门文章

  1. 短线看盘比较有效的方法
  2. 测试老江湖告诉你,测试猿如何优雅的甩锅?
  3. 优思学院:DMAIC六西格玛改进模型
  4. Redis基础-下载安装、配置、数据类型、指令、Jedis、持久化
  5. 线阵相机调帧率_(转)工业相机参数之帧率相关知识详解
  6. java环形buff_环形缓冲区.ringbuff(C#和java)
  7. CVE-2017-8464(震网三代)漏洞分析与复现
  8. 【论文汇总】CVPR2020语义分割医学图像分割paper汇总
  9. IBM朱辉:大数据分析的5个高复制使用场景及案例分享(含PPT)
  10. RCS(Real-time control systems) 库