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