一、开篇一问

一个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 操作的,所以,我们可以通过修改它,来改变后续的流程!
  1. 先从当前的容器对象取当前要创建的对象,当取出来的对象为null时开始着手创建对象!
  2. 做一系列的验证,比如验证这个类是否被排除、是否正在创建中、是否有依赖Bean【@DependsOn】注解、是否时单例等等!
  3. 验证通过之后,开始通过反射创建这个对象!
  4. 合并BeanDefinition ,这里涉及到Spring之前版本使用的父子容器的概念,属于另外一个知识点不做讲解!
  5. 判断当前对象是不是单例、是不是支持循环引用、是不是正在创建等!
  6. 执行第二个接口回调InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation()方法!
  • 它的执行时机时实例化完成之后,属性填充之前,它的返回值是一个布尔值,当返回false时,不做自动属性填充!
  1. 执行第三个接口回调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. 关于学习Python的一点学习总结(52->模块就是程序)
  2. JDK动态代理实现原理--转载
  3. Android——四大组件、六大布局、五大存储
  4. Paper之IEEERSJ:2009年~2019年机器人技术(IEEE机器人和自动化国际会议RSJ智能机器人与系统国际会议机器人技术:科学与系统机器人学报)历年最佳论文简介及其解读
  5. Vscode----热门插件超实用插件汇总(史上最全)
  6. dubbo配置文件xml校验报错
  7. 随想录(学习wrk的代码)
  8. openerp 常见问题 OpenERP在哪储存附件?(转载)
  9. Java面试题及答案整理(2022最新版)
  10. matlab磁盘内存,Matlab内存不足问题的解决【转】
  11. 数组根据条件筛选出满足条件的数据(数组里面是对象)
  12. 2012面试备忘录(夏季南京)
  13. 查看依赖关系 dependency walker(depends)
  14. 论文中绘制神经网络工具汇总
  15. java8,java9和java11的特性和区别!
  16. java set驱虫_由分子轨道理论可知, H 2 + 的键级为 0.5 ,并具有顺磁性_学小易找答案...
  17. python 爬取https://wall.alphacoders.com上的壁纸(入门级别)
  18. 数据结构(C语言版)严蔚敏(树、二叉树的相关概念笔记)
  19. 简支梁挠度计算公式推导_简支梁挠度计算公式
  20. Matlab机器人工具箱(0)——旋转与平移变换

热门文章

  1. 小白的算法初识课堂(part6)--广度优先搜索
  2. 走近分形与混沌(part13)--自然现象就其本质来说,是复杂而非线性的
  3. SAP Spartacus login 超链接和 login form 的区别
  4. SAP Spartacus 的会话管理 Session Management
  5. Angular 如何使用 InjectionToken 的方式得到当前 location 信息
  6. SAP Spartacus B2B 页面信息提示图标的弹出窗口显示实现逻辑
  7. SAP Cloud for Customer(C4C)里如何定义跨BO间的association
  8. SAP Spartacus B2B页面Banner Component的路由url是在哪里定义的
  9. Initializer provides no value for this binding element and the binding element has no default value
  10. 使用ABAP操作office Word文档