.動態(tài)代理
動態(tài)代理有以下特點:
1.代理對象,不需要實現(xiàn)接口
2.代理對象的生成,是利用JDK的API,動態(tài)的在內(nèi)存中構(gòu)建代理對象(需要我們指定創(chuàng)建代理對象/目標(biāo)對象實現(xiàn)的接口的類型)
3.動態(tài)代理也叫做:JDK代理,接口代理
JDK中生成代理對象的API
代理類所在包:java.lang.reflect.Proxy
JDK實現(xiàn)代理只需要使用newProxyInstance方法,但是該方法需要接收三個參數(shù),完整的寫法是:
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )
注意該方法是在Proxy類中是靜態(tài)方法,且接收的三個參數(shù)依次為:
- ClassLoader loader,:指定當(dāng)前目標(biāo)對象使用類加載器,獲取加載器的方法是固定的
- Class<?>[] interfaces,:目標(biāo)對象實現(xiàn)的接口的類型,使用泛型方式確認類型
- InvocationHandler h:事件處理,執(zhí)行目標(biāo)對象的方法時,會觸發(fā)事件處理器的方法,會把當(dāng)前執(zhí)行目標(biāo)對象的方法作為參數(shù)傳入
代碼示例:
接口類IUserDao.java以及接口實現(xiàn)類,目標(biāo)對象UserDao是一樣的,沒有做修改.在這個基礎(chǔ)上,增加一個代理工廠類(ProxyFactory.java),將代理類寫在這個地方,然后在測試類(需要使用到代理的代碼)中先建立目標(biāo)對象和代理對象的聯(lián)系,然后代用代理對象的中同名方法
代理工廠類:ProxyFactory.java
/**
* 創(chuàng)建動態(tài)代理對象
* 動態(tài)代理不需要實現(xiàn)接口,但是需要指定接口類型
*/
public class ProxyFactory{
//維護一個目標(biāo)對象
private Object target;
public ProxyFactory(Object target){
this.target=target;
}
//給目標(biāo)對象生成代理對象
public Object getProxyInstance(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("開始事務(wù)2");
//執(zhí)行目標(biāo)對象方法
Object returnValue = method.invoke(target, args);
System.out.println("提交事務(wù)2");
return returnValue;
}
}
);
}
}
測試類:App.java
/**
* 測試類
*/
public class App {
public static void main(String[] args) {
// 目標(biāo)對象
IUserDao target = new UserDao();
// 【原始的類型 class cn.itcast.b_dynamic.UserDao】
System.out.println(target.getClass());
// 給目標(biāo)對象纠亚,創(chuàng)建代理對象
IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
// class $Proxy0 內(nèi)存中動態(tài)生成的代理對象
System.out.println(proxy.getClass());
// 執(zhí)行方法 【代理對象】
proxy.save();
}
}
總結(jié):
代理對象不需要實現(xiàn)接口,但是目標(biāo)對象一定要實現(xiàn)接口,否則不能用動態(tài)代理