一、开篇一问

一个Spring Bean是Java对象吗?那么一个对象是Spring Bean吗?

带着这个问题我们一起来回顾Spring的生命周期流程,彻底了解一个类在Spring中究竟做了哪些操作!

我们先看一段代码!

诚然,相信只要是使用过Spring的人都应该知道,从Spring容器中获取的对象,里面的EmailServiceImpl是被Spring自动注入了的!

但是相同的点是,他们两个都是一个Java对象,都是加载在JVM里面的,那么至少我们现在可以回答的问题了:

SpringBean一定是一个java对象;但是一个Java对象却不一定是一个SpringBean!

那么我们是不是可以这样认为,只有被Spring管理的类,才能够称之为一个Bean,其他的都称之为对象!那么Spring是如何将一个类从一个普通的类转换为一个Spring Bean的呢?他究竟是经过了哪些步骤呢?我们一起探究一下!

二、Spring生命周期的大胆猜测

这里分享一个阅读源码的小技巧:捉大放小,连蒙带猜!8字真言,我们在阅读源码过程中,因为你要知道,每一个被开源出来的优秀框架,其源码的体系都是极其庞大复杂的,我们不能面面俱到,所以在看源码过程中一定不能被细枝末节缠住,一定要先理清楚整个框架的一个大致思想和大致的框架体系,再去搞那些细枝末节,其效率会好很多,其次在看源码过程中,我们一定要大胆的去想,去猜测,如果这个功能让你自己去写,你会怎么实现!

我们今天学习SpringBean的生命周期也是按照这个8字真言去学习,通过我们之前所学,Spring大致有以下的功能:

  1. 他会帮我们自动的创建对象然后保存起来!
  2. 他会帮我们完成属性的填充!
  3. 如果我们设置了Aop的功能,他会帮我们自动的代理,实现切面功能!

我们从平常的使用中,至少可以得知以上的三点,如果让你自己去实现,必会如何实现呢?

  • 首先他既然能够帮我们自己创建对象,那么他肯定是通过反射来创建的,通过反射来创建,就必定绕不过去要使用Class对象创建,那么我们如何获取Class对象呢? 去扫描项目,将指定的包下的加了注解的类文件切割获取Class名称,通过反射加载Class名称,反射创建java对象!
  • 我们要完成属性的填充,为了方便和性能方面,我肯定会把这些创建好的对象保存起来,无疑Map容器是最合适的!
  • 我们在创建一个对象完成之后,反射拿到里面的属性,如果需要填充,我们先去我们之前保存的容器里面去取,取不出来在反射吧这个依赖的属性创建出来,然后填充进对象再保存在容器里面,从而完成了属性的注入!
  • 填充完成属性之后,我们那当前对象,取与Aop逻辑进行对比,判断是否需要代理,不需要则创建完成,保存进Map容器,需要代理则对当前这个类进行jdk或者cglib的代理然后再保存进容器里面!

于是乎,我们自己实现了一个Spring管理一个Bean的所有过程,画个图,他大概长这样!

自己实现看起来,整个流程就很清晰,扫描、创建、注入、代理、保存一应俱全,但是Spring的实现方式远比我们自己实现的要复杂的多得多!

三、Spring的生命周期流程

Spring作者希望,Spring再着手管理一个Bean的时候,它希望能够让Spring的使用者能够插手,Spring把一个类对象变成一个Java Object的每一步,怎么理解呢?

比如我们买了一栋新房子,这个房子需要取装修,你自己去装修诚然不够专业,不能够面面俱到,所以是我们就找了一个装修公司帮助我们装修新房,于是装修公司就开始预先画好的图纸进行装修,但是在装修的过程中,你为了让自己的新家更加温馨,你想挂一些壁画在墙上,但是图纸上却没有!于是你就找装修公司,要求装修公司在新家的墙上挂上一些壁画!装修公司在接受到你的请求之后,就吩咐装修的工人在图纸之外去给你在墙上挂上壁画之后,然后再接着装修!

上面这个小故事有 这样几个角色,我们把它和Spring对照起来!

  • 你:代表框架的使用者!
  • 新房:代表一个Class文件,你自己也能够装修,但是不够专业,所以交给装修公司! 那么你自己创建对象可能某些使用用起来很麻烦,所以我们交给了Spring容器!
  • 装修公司:代表着Spring容器!
  • 图纸:代表预设步骤,Spring原本就存在的步骤!
  • 工人:Spring提供的各种接口!我们可以通过Spring工厂提供的接口做各种自定义的配置!

上面的小故事,大致可以描述Spring生命周期的核心思想!Spring再对一个Class文件实例化成具体的Spring Bean的时候,它提供了各种接口,由我们自己实现!然后再实例化过程中,不同的时机,去调用不同的接口!从而完成Spring的整个生命周期的创建!

Spring的生命周期大致分为以下部分!

  1. 扫描项目,将项目指定目录下的Class文件转换为Class对象!
  2. 读取Class对象属性包装为BeanDefinition,然后保存在一个Map中!(不难理解,他是为了后续创建或者读取这个类的信息更加方便取而创立的)
  3. 将全部的类转化为 BeanDefinition 并保存之后,开始调用第一个回调接口BeanFactoryPostProcessor#postProcessBeanFactory()!它的调用时机是将扫描到的Class文件转换为 BeanDefinition 之后调用的,我们可以通过回调的方法获取所有的BeanDefinition ,而后续的所有对Class的操作都是基于BeanDefinition 操作的,所以,我们可以通过修改它,来改变后续的流程!
  4. 先从当前的容器对象取当前要创建的对象,当取出来的对象为null时开始着手创建对象!
  5. 做一系列的验证,比如验证这个类是否被排除、是否正在创建中、是否有依赖Bean【@DependsOn】注解、是否时单例等等!
  6. 验证通过之后,开始通过反射创建这个对象!
  7. 合并BeanDefinition ,这里涉及到Spring之前版本使用的父子容器的概念,属于另外一个知识点不做讲解!
  8. 判断当前对象是不是单例、是不是支持循环引用、是不是正在创建等!
  9. 执行第二个接口回调InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation()方法!它的执行时机时实例化完成之后,属性填充之前,它的返回值是一个布尔值,当返回false时,不做自动属性填充!
  10. 执行第三个接口回调InstantiationAwareBeanPostProcessor#postProcessProperties()方法!
*   **他的执行时机是,实例化之后,属性填充检查之后,属性填充之前!它会返回一个属性,后续的属性填充会使用这个方法返回的值!我们可以在这个方法里面修改对应Bean的注入的值!**
  1. 填充属性到对象!
  2. 调用第四个回调接口BeanNameAware#setBeanName()方法!
*   **调用时机:属性填充给完毕后,调用初始化方法之前;它的功能是能获取bean的Name!**
  1. 调用第五个回调接口BeanClassLoaderAware#setBeanClassLoader()
*   **调用时机:`BeanNameAware`之后,他的功能是传入bean的类加载器;**
  1. 调用第六个回调接口BeanFactoryAware#setBeanFactory()!
*   **调用时机:`BeanClassLoaderAware`之后,用于设置beanFactory!**
  1. 调用第七个回调接口BeanPostProcessor#postProcessBeforeInitialization()方法
*   **调用时机是部分`Aware`之后,初始化方法之前!传入当前实例化好的对象和beanName,再初始化前做修改!**
  1. 回调第八个比较重要的生命周期的初始化方法,它可以是一个InitializingBean接口的bean,也可以是xml中配置的类,也可以是被加了@PostConstruct注解的方法!
*   **该方法内部逻辑可以用户自己编写,调用时机为:实例化完成之后调用!**
  1. 回调第九个回调接口 BeanPostProcessor#postProcessAfterInitialization()方法!
*   **该方法的调用时机为初始化方法执行之后,这里也是Bean实例化后的最后一步,也是SpringAop实现的重要的一步!**
  1. 注册销毁方法,以便Spring容器销毁的时候进行方法的销毁!

整体的方法流程示例图如下:

四、对应源码结构图

最后

大家看完有什么不懂的可以在下方留言讨论.
谢谢你的观看。
觉得文章对你有帮助的话记得关注我点个赞支持一下!

作者:螺旋升天
链接:https://juejin.im/post/6875847345121001486

java创建子类对象的步骤_一通Spring骚操作:我敢说没人比我更懂Java对象创建相关推荐

  1. java创建子类对象的步骤_一顿Spring骚操作:我敢说没有人比我更懂Java对象的创建!

    一.开篇一问 一个Spring Bean是Java对象吗?那么一个对象是Spring Bean吗? 带着这个问题我们一起来回顾Spring的生命周期流程,彻底了解一个类在Spring中究竟做了那些操作 ...

  2. 程序媛报告:调查了 12,000 名女性开发者发现,女性比男性更懂 Java!

    华为的中国芯将何庭波这位神秘低调的程序媛推入公众视野.在华为地位堪比任正非的她在谈及"工程师"这一身份时表示,"我觉得工程师本身就是一个很不了的职业,这也是我一生的荣耀和 ...

  3. 调查了 12,000 名女性开发者发现,女性比男性更懂 Java!

    华为的中国芯将何庭波这位神秘低调的程序媛推入公众视野.在华为地位堪比任正非的她在谈及"工程师"这一身份时表示,"我觉得工程师本身就是一个很不了的职业,这也是我一生的荣耀和 ...

  4. vc6创建dll文件的步骤_创建真正有用的产品支持页面的6步骤计划

    vc6创建dll文件的步骤 It'd be nice to think that your product UX is so exceptional that users won't ever nee ...

  5. java用redis缓存的步骤_详解在Java程序中运用Redis缓存对象的方法|chu

    这段时间一直有人问如何在Redis中缓存Java中的List 集合数据,其实很简单,常用的方式有两种: 1. 利用序列化,把对象序列化成二进制格式,Redis 提供了 相关API方法存储二进制,取数据 ...

  6. java 原子类能做什么_死磕 java原子类之终结篇(面试题)

    概览 原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会有任何线程上下文切换. 原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序不可以被打乱,也不可以被切割 ...

  7. java socket中属性详解_前端开发:关于Vue组件中的data属性值是函数而不是对象的详解...

    最近在搞关于前端开发的基础知识归纳,发现了不少经典知识点,那么本篇博文就来分享一个经典的知识点:Vue组件中的data属性值为什么是函数而不是对象.首先来了解一下Vue组件的使用理念:在Vue组件使用 ...

  8. java程序设计雷电游戏设计步骤_基于Java的飞机雷电射击游戏的设计任务书

    主要参考文献(资料): [1] Java 2游戏编程[M]. 清华大学出版社 , (美)ThomasPetchel著, 2005 [2] Java游戏引擎的开发与实现[J]. 何依林. 无线互联科技. ...

  9. java build path entries 为空_同事的代码简直没法看,我来教你如何更优雅的设计Java异常...

    点击上方蓝色字体,选择"设为星标" 回复"666"获取面试宝典 异常处理是程序开发中必不可少操作之一,但如何正确优雅的对异常进行处理确是一门学问,笔者根据自己的 ...

最新文章

  1. 机器学习数据预处理之缺失值:前向填充
  2. [转].Net连接池超时注意事项
  3. Android之文件数据存储
  4. 《机器学习实战》第5章 随机梯度上升算法
  5. 开发常见错误解决(3)VS2005调试程序出错,绑定句柄无效 Terminal Services
  6. RxJava 和 RxAndroid 五(线程调度)
  7. oracle 序列验证脚本,oracle 生成序列脚本
  8. corosync+openais+pacemaker构建高可用性集群
  9. 图 | 为什么存在关于图的研究
  10. 提高 Linux 开发效率的 5 个工具
  11. win7上python2.7连接mysql数据库
  12. 金蝶KIS专业版13.0视频教程
  13. 腾讯翻译君在线翻译怎么翻译整个文件_希腊语怎么翻译?教你两个超实用的翻译方法...
  14. 简单易用的程序多开器软件-V5程序多开器提供下载
  15. yylabel 加载html,YYLabel的简单使用
  16. matlab maps 指北针和比例尺,R 地图绘制-比例尺与指北针
  17. 域名指向 旧域名跳转到新域名
  18. 计算机中的标准差是哪个英语单词,标准差是什么意思
  19. 7-214 泰勒级数展开近似sin(x)的值7-215 求班级平均分7-216 同数异形体
  20. JS 中对象的深浅拷贝(ES3、ES5、ES6不同方法底层实现,一文搞清楚深浅拷贝面试常问题)

热门文章

  1. 一个C++程序员生产力,大概相当20个C程序员,200个java程序员?
  2. 性能优化篇(4):千万别使用CSS表达式
  3. php和python互动_PHP和Python 哪个更适合web开发?
  4. mybatis核心配置_MyBatis 核心配置综述之StatementHandler
  5. AJHG | 人类遗传学领域一流期刊推荐
  6. 连续时间采样及采样定理——MATLAB
  7. Mac用户装机必备——让 Mac 也能右键新建/剪切文件,多达 10 余项实用功能
  8. python最简单的账号密码验证_Python之简单的用户名密码验证
  9. 【ES6(2015)】Number
  10. 基于java 企业进销存管理系统设计(含源文件)