当创建对象时......
"程序員要?jiǎng)?chuàng)建對(duì)象了,快去西天請(qǐng)Spring'佛祖'。" ?一大早我就聽(tīng)到Tomcat在那里大喊。
“不就是創(chuàng)建一個(gè)對(duì)象嗎,你給JVM老大打個(gè)電話,請(qǐng)他在堆里邊new出來(lái)不就結(jié)了?無(wú)非就是一片兒內(nèi)存而已。”我問(wèn)道。
“唉,你不知道,這不僅僅是對(duì)象的創(chuàng)建,更是對(duì)象的裝配,要依賴注入,要初始化,又要代理什么的..... 這事兒Spring最擅長(zhǎng)。”Tomcat感慨到。
Spring慢悠悠地來(lái)了:“想安靜地喝一會(huì)兒茶都不行!讓我瞧瞧,這個(gè)要?jiǎng)?chuàng)建的對(duì)象是單例嗎? 嗯,果然是單例,也許之前創(chuàng)建過(guò)!讓我從我的緩存中找找有沒(méi)有! ”
Spring在他的緩存中扒拉半天,沒(méi)有找到,不滿地說(shuō):“緩存中沒(méi)有,看來(lái)得忙碌一番了。”
他請(qǐng)JVM老大把要?jiǎng)?chuàng)建對(duì)象的類PetStoreService 從方法區(qū)取過(guò)來(lái), 檢查了一下,嘆了口氣。
我問(wèn)道:“先生為何發(fā)愁啊?”
Spring說(shuō):“這個(gè)類沒(méi)有缺省構(gòu)造函數(shù),你看看,它依賴AccountDao和ItemDao,我還得先把這兩個(gè)bean給創(chuàng)建起來(lái),然后才能調(diào)用這個(gè)構(gòu)造函數(shù)創(chuàng)建這個(gè)PetStoreService對(duì)象,很麻煩的。”
public?PetStoreService(AccountDao?accountDao,?ItemDao?itemDao){this.accountDao?=?accountDao;this.itemDao?=?itemDao; }我估計(jì)這個(gè)所謂的bean 就是一個(gè)java對(duì)象, 怪不得Tomcat說(shuō)Spring做的主要是裝配工作,此言不虛啊。
Spring 把當(dāng)前的創(chuàng)建工作先放下,把工作重心轉(zhuǎn)移到AccountDao, 照例還是要先看構(gòu)造函數(shù),這次運(yùn)氣不錯(cuò),有個(gè)缺省的、無(wú)參數(shù)的構(gòu)造函數(shù)。
我說(shuō):“這下可以把它給new 出來(lái)了吧!”
Spring說(shuō):“不不,在讓JVM把它new 出來(lái)(這叫實(shí)例化)之前,我需要看看程序員有沒(méi)有給我設(shè)置一些需要預(yù)先執(zhí)行的代碼, 如果有,我得先執(zhí)行。 同理,實(shí)例化之后,還得做類似事情。”
Spring先執(zhí)行了所謂“前置代碼”,然后用反射的方式通知JVM把對(duì)象給創(chuàng)建起來(lái)。
注: 事實(shí)上在JVM那里還有一番折騰:
(1) 先執(zhí)行AccountDao中實(shí)例變量的初始化?
(2) 執(zhí)行實(shí)例代碼塊?
(3) 最后才是執(zhí)行構(gòu)造函數(shù),把AccountDao創(chuàng)建起來(lái),返回給Spring。
拿到了AccountDao的實(shí)例,Spring馬上執(zhí)行"實(shí)例化"以后的"后置代碼"。
我對(duì)他深表同情:“不容易,這樣一個(gè)對(duì)象就ok了,可以返回給程序員了吧?”
Spring說(shuō)道:“哪有那么簡(jiǎn)單!還有一步,叫做初始化,需要調(diào)用程序員指定的初始化方法。”
“初始化的前后也需要調(diào)用程序員設(shè)置的代碼吧?”
“沒(méi)錯(cuò),就是這樣,哎呀,你看看,這個(gè)AccountDao中還有@Autowired注解,需要注入一個(gè)User對(duì)象,我還得處理一下,真是麻煩!”
Spring再次放下手頭工作,開(kāi)始創(chuàng)建User對(duì)象,還是實(shí)例化,初始化,前置代碼,后置代碼,唉,這是一個(gè)遞歸的過(guò)程,我都懶得看了。
終于AcountDao對(duì)象創(chuàng)建完畢,接下來(lái)是ItemDao對(duì)象,又是一番同樣的折騰。
手持AccountDao對(duì)象和ItemDao對(duì)象, Spring終于可以開(kāi)始創(chuàng)建PetStoreService對(duì)象了。
實(shí)例化,初始化,前置代碼調(diào)用,后置代碼調(diào)用, 都是熟悉的配方、熟悉的味道。
PetStoreService的對(duì)象已經(jīng)創(chuàng)建出來(lái)(簡(jiǎn)稱petStore),也已經(jīng)初始化完畢,只剩下最后一步:初始化的后置代碼調(diào)用。
Spring看了看相關(guān)配置,心里咯噔了一下,說(shuō)到:“壞了,這個(gè)PetStoreService 用了聲明式事務(wù),我還得創(chuàng)建一個(gè)代理出來(lái)(簡(jiǎn)稱petStoreProxy),在這個(gè)proxy中來(lái)調(diào)用事務(wù)相關(guān)的代碼。”
“怎么創(chuàng)建代理對(duì)象?” 我問(wèn)道。
“我看看這個(gè)程序員想要的是petStore的兒子還是兄弟。”
“兒子? 兄弟?”
“哈哈,那是我的做的一個(gè)比喻,兒子就是這個(gè)PetStoreService類沒(méi)有實(shí)現(xiàn)接口, 我只好新創(chuàng)建一個(gè)類PetStoreServiceProxy,去繼承PetStoreService。 兄弟就是我創(chuàng)建的類PetStoreServiceProxy 和PetStoreService都實(shí)現(xiàn)同樣的接口。”
Spring看了看:“嗯,看來(lái)是'兒子',JVM老兄,你去把CGLib叫來(lái)吧,我得請(qǐng)他在運(yùn)行時(shí)生成一個(gè)新的Class,這個(gè)新的Class要繼承PetStoreService。”
CGLib是個(gè)熱情洋溢的小伙子,迅速地在內(nèi)存中創(chuàng)建了新的字節(jié)碼, 把我看得目瞪口呆,這個(gè)世界上還真有直接寫字節(jié)碼的人。
新的Class PetStoreProxy的字節(jié)碼已經(jīng)準(zhǔn)備好,JVM把他裝載到方法區(qū),Spring用它創(chuàng)建了一個(gè)對(duì)象出來(lái),終于返回給了程序員!
“程序員拿到的對(duì)象可不是PetStoreService啊,他會(huì)發(fā)現(xiàn)的吧?” 我善意地提醒Spring。
“沒(méi)關(guān)系,兩個(gè)類的'接口'都是相同的,除非他檢查對(duì)象的所屬類,否則是意識(shí)不到的。再說(shuō)了,哪個(gè)程序員會(huì)閑得無(wú)聊去查看對(duì)象所屬的類啊。”
"佛祖"Spring折騰了半天, 又去悠哉游哉地喝茶去了。
總結(jié)
以上是生活随笔為你收集整理的当创建对象时......的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 我也是一个线程,为什么每天累得像狗一样?
- 下一篇: 学习编程的加速度