我从容器来

2018 年 8 月 6 日 码农翻身

不知道谁把我创建出来的,反正我一出生就知道了自己的名字:  Account@736e9adb, 我的名字很有特色,Account表示类名, 736e9adb 相当于我的ID。


我环顾四周,大家的名字和我都差不多,只有一个家伙是例外,它叫做 Account$$BySpringCGLIB$$caa5f28f@4fccd51b


这名字怎么会这么长? 


我问他:“你这家伙的名称怎么和我们不一样呢? ”


“那当然了,” 他骄傲地说, “你们是直接new出来的,而我则是从容器来的!”


“容器?”


“是啊,你们没看到我的名字中有个BySpring吗? 我就是从Spring容器来的,容器负责我们的生命周期,管理我们的生老病死。在Sping容器中,我们这些Java对象被称为Bean。 对了,你知道吗? 除了Spring之外,还有其他‘容器’,比如Tomcat, Jetty等可以叫做Servlet的容器,管理Servlet的一生, Weblogic,Websphere等就是EJB的容器,当然现在EJB不怎么用了。”  这家伙知道的东西倒是不少。


“你说的生命周期是什么意思? Java 对象不就是new出来,然后使用,最后被垃圾回收吗?” 我问道。


“容器给我们规定了详细的生命周期,每个Spring的Bean都得严格执行生命周期的各个步骤。大致包括实例化,初始化,运行,销毁这么几个阶段。”  他说着给我们画了一张图。




“你们这些容器管理的'Bean'这么复杂啊? 我还以为new出来以后,就可以直接运行干活了。” 


“是啊, 其实生命周期在我们计算机软件界是很常见的事情,例如Servlet有生命周期,init->service->destroy。  React 组件也有生命周期 创建->更新->卸载,   Android的Activity也有生命周期,什么create, start, running, puase, stop ,destory等等, 大同小异。 这是非常细腻的管理,我们都很享受。”


我心里想,这些被容器管理的对象就是不一样,把短暂的一生分得这么细致。 


“可是,这么做的意义是什么?”  


“一个很重要的原因就是方便扩展啊,拿我们Spring容器来说,在生命周期的每个阶段开始和结束的时候,设置了一些钩子(Hook)函数,让大家随意扩展。”


(注:为了更容易读,我修改了方法名,和Spring源码不一致)


“钩子函数?”  我从来没有听说过。


“对啊,看到那些beforeXXX, afterXXX了吗? 这些都是钩子函数,如果你想在Bean的实例化或者初始化前后做点事情,就可以写一个类,当然得实现特定的接口(如InstantiationAwareBeanPostProcessor, BeanPostProcessor等),把这个类告诉我们的Spring容器,Spring就会在特定的时刻去调用了。”


“有这个必要吗?” 


“怎么没有必要?看到图中那个processPropertyValues()方法了吗,对,就是红色那个,在这个方法中,就可以实现Spring的@AutoWire 注解,把一个Bean依赖的其他对象给注入进来。 再比如那个afterInitialization()方法, 在里边创建一个对象的代理出来。这个代理在调用真正对象的方法之前,可以执行一些事务,安全,日志等操作,嗯, 人类把这种行为称为AOP。”


“代理 ? 怪不得你的名称和我们的不一样, 你的类名其实叫做Account$$BySpringCGLIB$$caa5f28f,你根本不是Account类,对不对?”  


我的这句话引起来大家的注意,其他Account对象纷纷围了过来。 要看看这个混入我们Accoun类家族的“奸细”。 


“嘿嘿,大家别紧张。 没错,我确实是从被增强了的一个新的Java Class创建的 ,不过我们也是一个家族啊,Account$$BySpringCGLIB$$caa5f28f 是运行时通过CGLib生成的, 是Account类的子类啊! 你们Account类拥有的方法, 我也都有,感谢伟大的多态, 在客户端看来,我就是个普通的Accout对象,客户端根本意识不到Spring容器在背后所做的小动作。”



//这里获得的account对象其实已经是被增强过了的类
//Account$$BySpringCGLIB$$caa5f28f
Account account = ctx.getBean("account");
//客户端还以为在调用原有的withdraw方法,但是由于多态的存在
//其实是增强类的withdraw方法,其中被添加了事务的功能。
account.withdraw();

(友情提示:可左右滑动)


“你这一招瞒天过海玩得可真溜啊。”  有个Account对象说道。 “你有这么强大的功能, 在我们这里不是抢我们的生意吗? 赶紧走吧!”


“走? 你让我去哪儿, 我也是堂堂正正的Java对象,也在Java Heap中生活!我还是个Singleton , 誓与容器一起共存亡!”


几个Account对象上来推搡他。


可是奇怪的事情发生了,那些个Account莫名其妙地消失了。


这个从Spring容器出来的Bean哈哈大笑:“瞧瞧,估计你们都是在一个for循环中生成的临时对象,生命短暂,很快被垃圾回收了! ”



与此同时,这个计算机系统的神在冷眼旁观,在他看来,根本就没有什么对象,什么容器,什么代理,它所看到的,只是内存中的那些二进制数据而已。


神的座右铭是:毁灭你,与你何干。


就在刚才,神调度了Java 虚拟机进程的一个线程运行,这个线程对内存的数据做了一些操作,仅此而已。


(完)


广告时间:使用CGLib,Java动态代理来实现AOP在我的课程《从零开始造Spring》中有详细讲解和代码实现。


码农翻身,用故事讲解技术本质, 更多精彩文章,请移步《码农翻身文章精华


登录查看更多
0

相关内容

【实用书】学习用Python编写代码进行数据分析,103页pdf
专知会员服务
194+阅读 · 2020年6月29日
已删除
将门创投
18+阅读 · 2019年2月18日
DiscuzX 3.4 Phar反序列化漏洞
黑客工具箱
8+阅读 · 2019年1月4日
这一次,彻底解决滚动穿透
IMWeb前端社区
35+阅读 · 2019年1月4日
Pipenv: 吹嘘自己无所不能,实际上没什么卵用
Python程序员
3+阅读 · 2018年12月21日
推荐一些适合小白练手的Python项目
数据挖掘入门与实战
6+阅读 · 2018年5月17日
浅谈浏览器 http 的缓存机制
前端大全
6+阅读 · 2018年1月21日
机器学习面试题精讲(一)
七月在线实验室
4+阅读 · 2018年1月11日
ROS 2正式版终于来了,还增加了这些新特性
量子位
3+阅读 · 2017年12月11日
python数据分析师面试题选
数据挖掘入门与实战
6+阅读 · 2017年11月21日
DPOD: Dense 6D Pose Object Detector in RGB images
Arxiv
5+阅读 · 2019年2月28日
Arxiv
5+阅读 · 2018年12月18日
Logically-Constrained Reinforcement Learning
Arxiv
3+阅读 · 2018年12月6日
VIP会员
相关资讯
已删除
将门创投
18+阅读 · 2019年2月18日
DiscuzX 3.4 Phar反序列化漏洞
黑客工具箱
8+阅读 · 2019年1月4日
这一次,彻底解决滚动穿透
IMWeb前端社区
35+阅读 · 2019年1月4日
Pipenv: 吹嘘自己无所不能,实际上没什么卵用
Python程序员
3+阅读 · 2018年12月21日
推荐一些适合小白练手的Python项目
数据挖掘入门与实战
6+阅读 · 2018年5月17日
浅谈浏览器 http 的缓存机制
前端大全
6+阅读 · 2018年1月21日
机器学习面试题精讲(一)
七月在线实验室
4+阅读 · 2018年1月11日
ROS 2正式版终于来了,还增加了这些新特性
量子位
3+阅读 · 2017年12月11日
python数据分析师面试题选
数据挖掘入门与实战
6+阅读 · 2017年11月21日
Top
微信扫码咨询专知VIP会员