1.1 為什么要用動(dòng)態(tài)代理
? ? ? ?學(xué)一個(gè)東西,感覺(jué)比較好的方式是問(wèn)自己它為什么要存在?學(xué)習(xí)java動(dòng)態(tài)代理首先需要理解為什么要?jiǎng)討B(tài)代理?使用代理是為了把一些通用的業(yè)務(wù)邏輯統(tǒng)一到代理中實(shí)現(xiàn),而使得被代理對(duì)象專(zhuān)注于自身功能的實(shí)現(xiàn)。比如計(jì)算一個(gè)類(lèi)中方法的運(yùn)行時(shí)間泽疆,如果使用靜態(tài)代理組合的方式實(shí)現(xiàn):
? ? ? ?如果只有一個(gè)兩個(gè)類(lèi)需要代理,寫(xiě)幾個(gè)代理類(lèi)倒也無(wú)所謂,但是當(dāng)需要使用代理的類(lèi)很多玲献,成百上千時(shí)殉疼,每個(gè)類(lèi)都需要一個(gè)代理類(lèi),這樣代理類(lèi)數(shù)目就太多了捌年,顯得太臃腫瓢娜,那么能不能只使用一個(gè)通用的代理類(lèi)來(lái)實(shí)現(xiàn)相同功能代理,避免對(duì)每個(gè)類(lèi)都實(shí)現(xiàn)一個(gè)代理礼预,這時(shí)動(dòng)態(tài)代理就可以派上用場(chǎng)了眠砾。
? ? ? java中的動(dòng)態(tài)代理是指在程序運(yùn)行過(guò)程中動(dòng)態(tài)的生成java文件并編譯成class文件,而不是像靜態(tài)代理那種在程序運(yùn)行前就有了相應(yīng)的代理class文件托酸。
? ? 需要?jiǎng)討B(tài)的生成陰影并編譯陰影部分的代碼褒颈,實(shí)現(xiàn)動(dòng)態(tài)編譯的方法有多種,比如jdk自帶的compiler 励堡, CGLIB谷丸, ASM(直接生成二進(jìn)制代碼)
1.2 jdk動(dòng)態(tài)代理的原理
? ? ? ? 如上圖所示,compile后會(huì)生成相應(yīng)的calss文件应结,然后把class文件load到內(nèi)存刨疼,由于此class文件不在ClassPath下,不能用常規(guī)的classloader來(lái)load,而是使用UrlClassLoader來(lái)加載揩慕,該代理實(shí)現(xiàn)了moveable接口游两,如果實(shí)現(xiàn)任意接口的代理呢?把要實(shí)現(xiàn)的接口名通過(guò)傳參的方式即可漩绵。
? ? ? 至此,不同的代理類(lèi)只需要寫(xiě)相應(yīng)的handler即可肛炮,不同的handler對(duì)應(yīng)不同邏輯的代理止吐,這樣對(duì)于同一類(lèi)型的代理只需要寫(xiě)一個(gè)handler就可以,而不是針對(duì)所有被代理的類(lèi)都寫(xiě)一個(gè)代理類(lèi)侨糟,這大大減少了冗余代碼和工作量碍扔。從上面也可以看出,jdk的動(dòng)態(tài)代理只能對(duì)接口代理秕重,要求被代理的類(lèi)需要實(shí)現(xiàn)某一接口不同,否則無(wú)法被代理。