Java動(dòng)態(tài)代理和反射機(jī)制詳解
反射機(jī)制
Java語言提供的一種基礎(chǔ)功能,通過反射,我們可以操作這個(gè)類或?qū)ο?,比如獲取這個(gè)類中的方法、屬性和構(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)系,也就是說,若代理類在程序運(yùn)行前就已經(jīng)存在了,這種情況就叫靜態(tài)代理
動(dòng)態(tài)代理
代理類在程序運(yùn)行時(shí)創(chuàng)建的代理方式。也就是說,代理類并不是在Java代碼中定義的,而是在運(yùn)行期間根據(jù)我們在Java代碼中的“指示”動(dòng)態(tài)生成的。
動(dòng)態(tài)代理比靜態(tài)代理的優(yōu)勢在于:
動(dòng)態(tài)代理可以很方便的對代理類的函數(shù)進(jìn)行統(tǒng)一的處理(invoke),而不是修改每個(gè)代理類的函數(shù),更靈活和擴(kuò)展。
JDK的動(dòng)態(tài)代理(依賴于接口)
- 在Java的動(dòng)態(tài)代理機(jī)制中,有兩個(gè)重要的類或接口,一個(gè)是InvocationHandler接口,另一個(gè)是Proxy類。
- InvocationHandler接口是給動(dòng)態(tài)代理類實(shí)現(xiàn)的,負(fù)責(zé)處理被代理對象的操作
- Proxy類是用來創(chuàng)建動(dòng)態(tài)代理類實(shí)例對象的,只有得到這個(gè)對象,才能調(diào)用需要代理的方法。
- 動(dòng)態(tài)代理的代理類是在靜態(tài)代理類上進(jìn)行修改,將動(dòng)態(tài)代理類實(shí)現(xiàn)InvocationHandler接口,重寫Invoke方法,Invoke方法通過傳入的被代理類方法和參數(shù)來執(zhí)行。
如下實(shí)例:
public interface AppService {
void createApp(String name);
void deleteApp(String name);
}
//代理類(比如微商代理)
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; //委托類(被代理類)的實(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)對象的方法 (調(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)對象 (代理類的對象)
//接下來創(chuàng)建代理對象
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)方式是依賴于接口的,首先使用接口來定義好操作規(guī)范。
* 2、通過proxy類產(chǎn)生的代理對象調(diào)用被代理對象的操作。
* 3、而這個(gè)操作又被分發(fā)給InvocationHandler接口的invoke方法具體執(zhí)行
*
* 在java的動(dòng)態(tài)代理機(jī)制中,有兩個(gè)重要的類或接口,一個(gè)是InvocationHandler接口、另一個(gè)則是 Proxy類,這個(gè)類和接口是實(shí)現(xiàn)我們動(dòng)態(tài)代理所必須用到的。
InvocationHandler接口是給動(dòng)態(tài)代理類實(shí)現(xiàn)的,負(fù)責(zé)處理被代理對象的操作的,而Proxy是用來創(chuàng)建動(dòng)態(tài)代理類實(shí)例對象的,因?yàn)橹挥械玫搅诉@個(gè)對象我們才能調(diào)用那些需要代理的方法。
*
* 此方法的參數(shù)含義如下
proxy:代表動(dòng)態(tài)代理對象
method:代表正在執(zhí)行的方法
args:代表當(dāng)前執(zhí)行方法傳入的實(shí)參
返回值:表示當(dāng)前執(zhí)行方法的返回值
*
* 如上:
* 使用了Proxy類的newProxyInstance方法生成代理對象,然后用這個(gè)對象去調(diào)用createApp()和deleteApp()方法,
* 其實(shí)系統(tǒng)會將這2個(gè)方法分發(fā)給invoke()方法區(qū)執(zhí)行。其中proxy對象的類是系統(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來實(shí)現(xiàn)動(dòng)態(tài)代理類。
攔截器MethodInterceptor中就是由MethodProxy的InvokSuper方法調(diào)用代理方法的。
MethodProxy類生成代理方法和代理方法的簽名。
JDK動(dòng)態(tài)代理和Cglib動(dòng)態(tài)代理的區(qū)別:
- JDK動(dòng)態(tài)代理是實(shí)現(xiàn)了被代理對象的接口,Cglib是繼承了被代理對象。
- Cglib因?yàn)槭抢^承機(jī)制,所以無法代理被final修飾的方法。
- JDK和Cglib都是在運(yùn)行期間生產(chǎn)字節(jié)碼,JDK是直接寫class字節(jié)碼,Cglib使用ASM框架寫class字節(jié)碼;cglib代理實(shí)現(xiàn)更復(fù)雜,生成代理類比JDK效率低。
- JDK調(diào)用代理方法,是通過反射實(shí)現(xiàn)機(jī)制調(diào)用,cglib是通過Fashclass機(jī)制直接調(diào)用方法,效率更高。
Fastcalss機(jī)制:
為代理類和被代理類個(gè)生成一個(gè)class,這個(gè)class會為代理類或被代理類的方法分配一個(gè)index。
這個(gè)index當(dāng)做一個(gè)入?yún)?,F(xiàn)ashclass就可以直接定位要調(diào)用的方法,并直接進(jìn)行調(diào)用。這樣省去了反射調(diào)用,所以效率高。
以上所述是小編給大家介紹的Java動(dòng)態(tài)代理和反射機(jī)制詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時(shí)回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
IDEA(2022.2)搭建Servlet基本框架超詳細(xì)步驟
這篇文章主要給大家介紹了關(guān)于IDEA(2022.2)搭建Servlet基本框架超詳細(xì)步驟,Servlet容器負(fù)責(zé)Servlet和客戶的通信以及調(diào)用Servlet的方法,Servlet和客戶的通信采用"請求/響應(yīng)"的模式,需要的朋友可以參考下2023-10-10
Java 客戶端向服務(wù)端上傳mp3文件數(shù)據(jù)的實(shí)例代碼
這篇文章主要介紹了Java 客戶端向服務(wù)端上傳mp3文件數(shù)據(jù)的實(shí)例代碼,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-09-09
SpringBoot整合Elasticsearch游標(biāo)查詢的示例代碼(scroll)
這篇文章主要介紹了SpringBoot整合Elasticsearch游標(biāo)查詢(scroll),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10
SpringBoot2整合Ehcache組件實(shí)現(xiàn)輕量級緩存管理
EhCache是一個(gè)純Java的進(jìn)程內(nèi)緩存框架,具有快速、上手簡單等特點(diǎn),是Hibernate中默認(rèn)的緩存提供方。本文講述下SpringBoot2 整合Ehcache組件的步驟2021-06-06
Aop動(dòng)態(tài)代理和cglib實(shí)現(xiàn)代碼詳解
這篇文章主要介紹了Aop動(dòng)態(tài)代理和cglib實(shí)現(xiàn)代碼詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-12-12
后端返回各種圖片形式在前端的轉(zhuǎn)換及展示方法對比
這篇文章主要給大家介紹了關(guān)于后端返回各種圖片形式在前端的轉(zhuǎn)換及展示方法對比的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2023-06-06
JDK自帶的序列化方式優(yōu)缺點(diǎn)及實(shí)現(xiàn)原理面試精講
這篇文章主要為大家介紹了JDK自帶的序列化方式優(yōu)缺點(diǎn)及實(shí)現(xiàn)原理面試精講,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
Mybatis中resultMap標(biāo)簽和sql標(biāo)簽的設(shè)置方式
這篇文章主要介紹了Mybatis中resultMap標(biāo)簽和sql標(biāo)簽的設(shè)置方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
Springboot在有鎖的情況下正確使用事務(wù)的實(shí)現(xiàn)代碼
這篇文章主要介紹了Springboot在有鎖的情況下如何正確使用事務(wù),今天通過一個(gè)實(shí)驗(yàn)給大家分析一下商品超賣問題,模擬場景分析通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-12-12

