前面我們已經(jīng)介紹了代理的好處了,前面寫的是靜態(tài)代理,要手工創(chuàng)建代理類。下面,我們說說它的問題,我們發(fā)現(xiàn),代理類和老板類都實(shí)現(xiàn)了一個接口,如果業(yè)務(wù)繁多,這樣的接口會有很多,如果代理的功能是通用的,就需要對每個接口創(chuàng)建相應(yīng)的代理類,這個叫類爆炸(類太多了),所以Java提供了動態(tài)代理,即程序運(yùn)行時動態(tài)創(chuàng)建代理類的.class.
來看一下動態(tài)代理:
JDK動態(tài)代理中包含一個類和一個接口:
InvocationHandler接口: 代表代理對象關(guān)聯(lián)的處理代碼
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
參數(shù)說明:
Object proxy:指被代理的對象(老板)
Method method:要調(diào)用的方法
Object[] args:方法調(diào)用時所需要的參數(shù)
調(diào)用代理對象的所有方法都會被替換成執(zhí)行InvocationHandler的invoke()方法
Proxy類:
Proxy類是創(chuàng)建代理對象的工具類,此類提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h) throws IllegalArgumentException
參數(shù)說明:
ClassLoader loader:類加載器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子類實(shí)例
與靜態(tài)代理類對照的是動態(tài)代理類,動態(tài)代理類的字節(jié)碼在程序運(yùn)行時由Java反射機(jī)制動態(tài)生成,無需程序員手工編寫它的源代碼。動態(tài)代理類不僅簡化了編程工作,而且提高了軟件系統(tǒng)的可擴(kuò)展性,因?yàn)镴ava 反射機(jī)制可以生成任意類型的動態(tài)代理類。java.lang.reflect 包中的Proxy類和InvocationHandler 接口提供了生成動態(tài)代理類的能力。
動態(tài)代理示例:
//1.演出的接口
public interface Inter{
//演出
public void show();
}
//2.某明星(被代理的類,可以理解為老板)
public class 明星A implements Inter { //實(shí)現(xiàn)表演接口
//明星表演
public void show() {
System.out.println("明星A賣力表演中。。。");
}
}
/**
* 3.JDK動態(tài)代理關(guān)聯(lián)的處理代碼
*/
public class InvocationHandlerImpl implements InvocationHandler {
/*
這個target是經(jīng)紀(jì)人要代理的明星,是Object類型,如果經(jīng)紀(jì)人這個功能是通用的,可以適用于所有要被代理的類.而不用為每種類型的明星都創(chuàng)建一個代理類,這就是動態(tài)代理的好處,不像靜態(tài)代理那樣,要為很多老板類創(chuàng)建代理類
*/
private Object target;
/**
* 綁定一個明星并返回一個代理對象(一個經(jīng)紀(jì)人)
* @param target
* @return
*/
public Object bind(Object target) { //傳入一個要被代理的具體的明星對象
this.target = target;
//返回代理對象(這個代理對象實(shí)現(xiàn)了和 target一樣的接口)
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
@Override
/**
* 調(diào)用代理對象的方法都會執(zhí)行invoke()方法
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("拍戲前簽合同"); //拍戲的前期工作
Object result = method.invoke(target, args); //中間讓明星去表演
System.out.println("拍戲結(jié)束后的后期工作"); //拍戲后的后期工作
return result;
}
}
4.客戶端調(diào)用
public class TestProxy {
public static void main(String[] args) {
//創(chuàng)建關(guān)聯(lián)的處理代碼實(shí)現(xiàn)類
InvocationHandlerImpl handler = new InvocationHandlerImpl();
//返回代理對象(這個代理對象的.class是動態(tài)生成的)
Inter proxy = (Inter) handler .bind(new 明星A());
//調(diào)用代理對象的show方法,實(shí)際執(zhí)行的是handler 的invoke()方法
proxy .show();
}
}
可能大家覺得這個動態(tài)代理也沒什么用?是的,在普通開發(fā)中,這個是很少用的,
但在搭建系統(tǒng)框架和底層開發(fā)中,是會用到的。
JDK的動態(tài)代理依靠接口實(shí)現(xiàn),如果有些類并沒有實(shí)現(xiàn)接口,則不能使用JDK的動態(tài)代理,這就要使用cglib動態(tài)代理了。