去字节面试,直接让人出门左拐:Bean 生命周期都不知道!

网站建设3年前发布
42 0 0

大家好,我是楼仔!,Spring Bean 的生命周期,面试时非常容易问,这不,前段时间就有个粉丝去字节面试,因为不会回答这个问题,一面都没有过。,如果只讲基础知识,感觉和网上大多数文章没有区别,但是我又想写得稍微深入一点。,考虑很多同学不喜欢看源码,我就把文章分为 2 大部分,前面是基础知识,主要方便大家面试和学习,后面是源码部分,对源码感兴趣的同学可以继续往后面看。,2023030601491933f416b80b5389010ed739905f682c582d06eb519,IoC,控制反转,想必大家都知道,所谓的控制反转,就是把 new 对象的权利交给容器,所有的对象都被容器控制,这就叫所谓的控制反转。,IoC 很好地体现了面向对象设计法则之一 —— 好莱坞法则:“别找我们,我们找你”,即由 IoC 容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。,理解好 IoC 的关键是要明确 “谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”。,2023030601492766d9e6c25484f536eca1422f7bc19c7c1d243c199,传统 Java SE 程序设计,我们直接在对象内部通过 new 进行创建对象,是程序主动去创建依赖对象。而 IoC 是由专门一个容器来创建这些对象,即由 IoC 容器来控制对象的创建。,为何是反转,哪些方面反转了?,有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转,而反转则是由容器来帮忙创建及注入依赖对象。,对 Prototype Bean 来说,当用户 getBean 获得 Prototype Bean 的实例后,IOC 容器就不再对当前实例进行管理,而是把管理权交由用户,此后再 getBean 生成的是新的实例。,所以我们描述 Bean 的生命周期,都是指的 Singleton Bean。,2023030601484062a53f545024028796a226d7ae535ec1a4e335126,Bean 生命周期过程:,整个执行流程稍微有些抽象,下面我们通过代码,来演示执行流程。,创建一个 LouzaiBean。,自定义一个后处理器 MyBeanPostProcessor。,applicationContext.xml 配置文件(部分)。,测试入口:,执行结果:,这个流程非常清晰,Bean 生命周期流程图能完全对应起来。,我们发现,整个生命周期有很多扩展过程,大致可以分为 4 类:,注意:Spring 的版本是 5.2.15.RELEASE,否则和我的代码不一样!!!,上面的知识,网上其实都有,下面才是我们的重头戏,让你跟着我走一遍代码流程。,2023030601484108c711848456b709af935316cd1daf53115824850,20230306014841950536a80acb4611f9b8630c7beabe6fea9f88243,这里需要多跑几次,把前面的 beanName 跳过去,只看 louzaiBean。,20230306014841d7daac718409ead083e38975e8788e8c7c4b64170,20230306014921056d7d34711d0e986d48762d24a8013a6b245b472,进入 doGetBean(),从 getSingleton() 没有找到对象,进入创建 Bean 的逻辑。,20230306014843484088748405a0cc4fa686a551b10138dfee23163,20230306014921c79db7b2339b394aae2198c69bf799192c5fe7528,进入 doCreateBean() 后,调用 createBeanInstance()。,20230306014843a65a7f321783c8549af736adfc5e68723cc81e314,进入 createBeanInstance() 后,调用 instantiateBean()。,20230306014922e5d28b0703d7ed4bb8f6394d134e0137b50afa113,20230306014845821483165446aef6432830bf44bec40f142598477,202303060148451525b8a823cbb08e035915cb5aadfc776d03e4752,20230306014846b9947b913a48adaec1c13009a3003f62a3a75e241,2023030601484745a57f580445eb104f3804e7a2824708523e92233,走进示例 LouzaiBean 的方法,实例化 LouzaiBean。,2023030601484743ed79b92b9095eacd6044d2ab005158673c98243,再回到 doCreateBean(),继续往后走,进入 populateBean()。,这个方法非常重要,里面其实就是依赖注入的逻辑,不过这个不是我们今天的重点,大家如果对依赖注入和循环依赖感兴趣,可以翻阅我之前的文章。,2023030601492258b12bb155e4f55fe78543d1e929b401f5d4aa558,进入 populateBean() 后,执行 applyPropertyValues(),20230306014922281de7325f665498281959a3469a9659202347951,进入 applyPropertyValues(),执行 bw.setPropertyValues(),20230306014849a15142263caf3fe54cb0653f666ec6e578b918459,20230306014850444070a59825c14da9a8345b4c3013284b0411677,2023030601485004f5dad66b4e208f4cf31514eccf170c7a5d76136,20230306014850c8d9d9131d91f4cfee32357d86ff4794519eb0250,进入 processLocalProperty(),执行 ph.setValue()。,2023030601485017d616e9194000d7614336472e6ea9b17621f2985,2023030609551186b2b6621e940972b71237c63a2f6c887038e1528,2023030601492443cf6b67684b2cb2ae61254c676d074f3ab034862,走进示例 LouzaiBean 的方法,给 LouzaiBean 赋值 name。,20230306014852a1fa7e416287e80feea59787f4dbef37ab7d1d783,到这里,populateBean() 就执行完毕,下面开始初始化 Bean。,我们继续回到 doCreateBean(),往后执行 initializeBean()。,2023030601485274786ba743867e395e15238a1c090e74877a2d232,20230306014853a78675093cfafd4eb6781321017fb11d1d5a10925,20230306014854363957862ec97d3a729472f3173ede6176aaf0936,走进示例 LouzaiBean 的方法,给 LouzaiBean 设置 BeanName。,20230306014854777fcd351f41726b5eb437a3ac3e1506f2f742706,回到 invokeAwareMethods()。,20230306014925525b2f056a7ad8c1320308e69eb88befb8accb118,走进示例 LouzaiBean 的方法,给 LouzaiBean 设置 BeanFactory。,20230306014856927a96b134d354e56a5832a20283ef77f5cccb110,第一次回到 initializeBean(),执行下面逻辑。,20230306014856631dd0d57153b41b5e8510fcb3a30e382ef579194,这里需要多循环几次,找到 MyBeanPostProcessor 的策略方法。,20230306014856e2e126325d9c17cbd6d563e7bbc56d4340c858977,我们自己定义的后置处理方法。,2023030601492535ea5f9581705698eac366863e5c8f9faed23d683,第二次回到 initializeBean(),执行下面逻辑。,20230306014857b74830a05188e4644e23292f1c0dd337f91d12247,2023030601485811f3f844426bcf149ce9070df71053c4ec1e9d297,走进示例 LouzaiBean 的方法,执行 afterPropertiesSet()。,20230306014925610dabf743f955ff4d8650bc010afc481d71f4560,返回 invokeInitMethods(),执行下面逻辑。,20230306014859c4a1519745f47fbcda61216ca49274e9f51a41617,进入 invokeCustomInitMethod(),执行下面逻辑。,2023030601485998d639b27590617c16a5946dcce723b5881360738,走进示例 LouzaiBean 的方法,执行 init()。,2023030601490075a02348758a0b6cb97209195185f4774ebd7a669,第三次回到 initializeBean(),执行下面逻辑。,20230306014900b10436b9997e2181dbb03107a04749dbe0a64d142,20230306014928f4a4872918f6d7cf9be691e01e6ff2efd3d51c853,我们自己定义的后置处理方法。,202303060149027332b9274150f012b5d8787b78e0bc09ce7f7c272,到这里,初始化的流程全部结束,都是围绕 initializeBean() 展开。,2.4 销毁,当 louzaiBean 生成后,后面开始执行销毁操作,整个流程就比较简单。,20230306014928111860d68ee7cb1d01c691ec727d8d52afd03b934,2023030601490369ff17364ffbe5cdb54819e53c1eaa15f254d1542,20230306014903b4c3a504146328c89271006a668f427a22e0b9505,202303060149033158dff30840515977e385f2f555c7a672d968586,20230306014904e95e3ef72c23cbef0ec3874e50f56e5c435740460,20230306014929b74b0ba84ce669b93ad5297e9a69fc1377b217491,20230306014905e1bc38263f37b133ab6931a618cf6bfdd97ccd246,2023030601492963eabc6435296488511042ae2f5d14d9099426783,2023030601490724c1ebe968b36532787911624558d9c99fc1d1711,20230306014907645c8cc98fd69ada37e9799999404e6ee338b3591,走进示例 LouzaiBean 的方法,执行 destroy()。,202303060149074297d4d7397c8dca86d2344b562484c1f733fd288,回到 destroy(),执行下面逻辑。,20230306014908f9ebfe26301979ce01a0024d73b6af80f0bcd3712,202303060149089480aa4146abe7b56a67742a1eac09c2a9df6b860,20230306014930531675a7812c20b4d72843d82e393c34af4b28805,走进示例 LouzaiBean 的方法,执行 destroyMethod()。,202303060149315474633218b090ac07895205334bab047a251c399,到这里,所有的流程全部结束,文章详细描述所有的代码逻辑流转,你可以完全根据上面的逻辑,自己 debug 一遍。,我们再回顾一下几个重要的方法:,先执行 aware 的 BeanNameAware、BeanFactoryAware 接口;,再执行 BeanPostProcessor 前置接口;,然后执行 InitializingBean 接口,以及配置的 init();,最后执行 BeanPostProcessor 的后置接口。,destory():先执行 DisposableBean 接口,再执行配置的 destroyMethod()。,对于 populateBean(),里面的核心其实是对象的依赖注入,这里也是常考的知识点,比如循环依赖,大家如果对这块也感兴趣,可以私下和我交流。,今天的源码解析就到这,Spring 相关的源码,还有哪些是大家想学习的呢,可以给楼仔留言。,这篇文章肝了我一个星期,原创不易,大家的点赞和分享,是我继续创作的最大动力!,三分恶的《Spring Bean生命周期,好像人的一生。。》:https://juejin.cn/post/7075168883744718856

© 版权声明

相关文章