不知道谁把我创建出来的,反正我一出生就知道了自己的名字: 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》中有详细讲解和代码实现。
码农翻身,用故事讲解技术本质, 更多精彩文章,请移步《码农翻身文章精华》