反射機(jī)制
創(chuàng)新互聯(lián)公司專(zhuān)注于山亭網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠(chéng)為您提供山亭營(yíng)銷(xiāo)型網(wǎng)站建設(shè),山亭網(wǎng)站制作、山亭網(wǎng)頁(yè)設(shè)計(jì)、山亭網(wǎng)站官網(wǎng)定制、微信小程序定制開(kāi)發(fā)服務(wù),打造山亭網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供山亭網(wǎng)站排名全網(wǎng)營(yíng)銷(xiāo)落地服務(wù)。
Java語(yǔ)言提供的一種基礎(chǔ)功能,通過(guò)反射,我們可以操作這個(gè)類(lèi)或?qū)ο?,比如獲取這個(gè)類(lèi)中的方法、屬性和構(gòu)造方法等。
動(dòng)態(tài)代理:分為JDK動(dòng)態(tài)代理、cglib動(dòng)態(tài)代理(spring中的動(dòng)態(tài)代理)。
靜態(tài)代理
預(yù)先(編譯期間)確定了代理者與被代理者之間的關(guān)系,也就是說(shuō),若代理類(lèi)在程序運(yùn)行前就已經(jīng)存在了,這種情況就叫靜態(tài)代理
動(dòng)態(tài)代理
代理類(lèi)在程序運(yùn)行時(shí)創(chuàng)建的代理方式。也就是說(shuō),代理類(lèi)并不是在Java代碼中定義的,而是在運(yùn)行期間根據(jù)我們?cè)贘ava代碼中的“指示”動(dòng)態(tài)生成的。
動(dòng)態(tài)代理比靜態(tài)代理的優(yōu)勢(shì)在于:
動(dòng)態(tài)代理可以很方便的對(duì)代理類(lèi)的函數(shù)進(jìn)行統(tǒng)一的處理(invoke),而不是修改每個(gè)代理類(lèi)的函數(shù),更靈活和擴(kuò)展。
JDK的動(dòng)態(tài)代理(依賴(lài)于接口)
在Java的動(dòng)態(tài)代理機(jī)制中,有兩個(gè)重要的類(lèi)或接口,一個(gè)是InvocationHandler接口,另一個(gè)是Proxy類(lèi)。
InvocationHandler接口是給動(dòng)態(tài)代理類(lèi)實(shí)現(xiàn)的,負(fù)責(zé)處理被代理對(duì)象的操作
Proxy類(lèi)是用來(lái)創(chuàng)建動(dòng)態(tài)代理類(lèi)實(shí)例對(duì)象的,只有得到這個(gè)對(duì)象,才能調(diào)用需要代理的方法。
動(dòng)態(tài)代理的代理類(lèi)是在靜態(tài)代理類(lèi)上進(jìn)行修改,將動(dòng)態(tài)代理類(lèi)實(shí)現(xiàn)InvocationHandler接口,JAVA電子書(shū)重寫(xiě)Invoke方法,Invoke方法通過(guò)傳入的被代理類(lèi)方法和參數(shù)來(lái)執(zhí)行。
如下實(shí)例:
public interface AppService { void createApp(String name); void deleteApp(String name); } //代理類(lèi)(比如微商代理) public class AppServiceImpl implements AppService{ @Override public void createApp(String name) { System.out.print("App["+name+"] has been created."); } @Override public void deleteApp(String name) { System.out.print("App["+name+"] has been delete."); } } import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class LoggerInterceptor implements InvocationHandler { private Object target; //委托類(lèi)(被代理類(lèi))的實(shí)例,比如廠家 public LoggerInterceptor(Object target){ this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args)throws Throwable { System.out.println("Entered "+target.getClass().getName()+"-"+method.getName()+",with arguments{"+args[0]+"}"); Object result = method.invoke(target, args); //調(diào)用目標(biāo)對(duì)象的方法 (調(diào)用廠家的方法(createApp)及參數(shù)(Kevin Test)) System.out.println("Before return:"+result); return result; } }
import java.lang.reflect.Proxy; public class test { public static void main(String[] args) { AppService target = new AppServiceImpl();//生成目標(biāo)對(duì)象 (代理類(lèi)的對(duì)象) //接下來(lái)創(chuàng)建代理對(duì)象 AppService proxy = (AppService) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new LoggerInterceptor(target)); proxy.createApp("Kevin Test1"); proxy.deleteApp("Kevin Test2"); } }/** * 1、jdk的動(dòng)態(tài)代理實(shí)現(xiàn)方式是依賴(lài)于接口的,首先使用接口來(lái)定義好操作規(guī)范。 * 2、通過(guò)proxy類(lèi)產(chǎn)生的代理對(duì)象調(diào)用被代理對(duì)象的操作。 * 3、而這個(gè)操作又被分發(fā)給InvocationHandler接口的invoke方法具體執(zhí)行 * * 在java的動(dòng)態(tài)代理機(jī)制中,有兩個(gè)重要的類(lèi)或接口,一個(gè)是InvocationHandler接口、另一個(gè)則是 Proxy類(lèi),這個(gè)類(lèi)和接口是實(shí)現(xiàn)我們動(dòng)態(tài)代理所必須用到的。 InvocationHandler接口是給動(dòng)態(tài)代理類(lèi)實(shí)現(xiàn)的,負(fù)責(zé)處理被代理對(duì)象的操作的,而Proxy是用來(lái)創(chuàng)建動(dòng)態(tài)代理類(lèi)實(shí)例對(duì)象的,因?yàn)橹挥械玫搅诉@個(gè)對(duì)象我們才能調(diào)用那些需要代理的方法。 * * 此方法的參數(shù)含義如下 proxy:代表動(dòng)態(tài)代理對(duì)象 method:代表正在執(zhí)行的方法 args:代表當(dāng)前執(zhí)行方法傳入的實(shí)參 返回值:表示當(dāng)前執(zhí)行方法的返回值 * * 如上: * 使用了Proxy類(lèi)的newProxyInstance方法生成代理對(duì)象,然后用這個(gè)對(duì)象去調(diào)用createApp()和deleteApp()方法, * 其實(shí)系統(tǒng)會(huì)將這2個(gè)方法分發(fā)給invoke()方法區(qū)執(zhí)行。其中proxy對(duì)象的類(lèi)是系統(tǒng)幫我們動(dòng)態(tài)創(chuàng)建了,其實(shí)實(shí)現(xiàn)了我們的業(yè)務(wù)接口AppService * */
cglib動(dòng)態(tài)代理(繼承方式)
cglib動(dòng)態(tài)代理中使用MethodInterceptor來(lái)實(shí)現(xiàn)動(dòng)態(tài)代理類(lèi)。
攔截器MethodInterceptor中就是由MethodProxy的InvokSuper方法調(diào)用代理方法的。
MethodProxy類(lèi)生成代理方法和代理方法的簽名。
JDK動(dòng)態(tài)代理和Cglib動(dòng)態(tài)代理的區(qū)別:
1、JDK動(dòng)態(tài)代理是實(shí)現(xiàn)了被代理對(duì)象的接口,Cglib是繼承了被代理對(duì)象。
2、Cglib因?yàn)槭抢^承機(jī)制,所以無(wú)法代理被final修飾的方法。
3、JDK和Cglib都是在運(yùn)行期間生產(chǎn)字節(jié)碼,JDK是直接寫(xiě)class字節(jié)碼,Cglib使用ASM框架寫(xiě)class字節(jié)碼;cglib代理實(shí)現(xiàn)更復(fù)雜,生成代理類(lèi)比JDK效率低。
4、JDK調(diào)用代理方法,是通過(guò)反射實(shí)現(xiàn)機(jī)制調(diào)用,cglib是通過(guò)Fashclass機(jī)制直接調(diào)用方法,效率更高。
Fastcalss機(jī)制:
為代理類(lèi)和被代理類(lèi)個(gè)生成一個(gè)class,這個(gè)class會(huì)為代理類(lèi)或被代理類(lèi)的方法分配一個(gè)index。
這個(gè)index當(dāng)做一個(gè)入?yún)?,F(xiàn)ashclass就可以直接定位要調(diào)用的方法,并直接進(jìn)行調(diào)用。這樣省去了反射調(diào)用,所以效率高。