一、基本簡介
在java的java.lang.reflect包下提供了一個Proxy類和InvocationHandler接口,通過使用這個類和接口可以生成JDK動態代理類或動態代理對象。
Proxy類提供了兩個方法:
static Class< ? > getProxyClass( ClassLoader loader,Class< ? > … interfaces) :
創建一個動態代理類所對應的Class對象,該代理類將實現interfaces所指定的多個接口。
第一個參數指定生成動態代理類的類加載器。static Object newProxyInstance( ClassLoader loader,Class< ? >[] interfaces,InvocationHandler h):
直接創建一個動態代理對象,該代理對象的實現類實現了Interfaces指定的系列接口,執行代理對象的每個方法都會被替換成InvocationHandler對象的invoke方法。
實際上,即使採用第一種方法生成動態代理類之後,如果程序需要通過該代理類來創建代理對象,還是需要傳入一個InvocationHandler實例。
代碼示例:
try {
//創建一個InvocationHandler對象
InvocationHandler invocationHandler = new MyInvocationHandler();
//使用Proxy生成一個動態代理類proxyClass
Class proxyClass= Proxy.getProxyClass(Foo.class.getClassLoader(),Foo.class);
//獲取一個proxyClass類帶InvocationHandler參數的構造器
Constructor constructor = proxyClass.getConstructor(InvocationHandler.class);
//調用constructor的newInstance方法生成動態代理實例
Foo foo = (Foo) constructor.newInstance(invocationHandler);
} catch (Exception e) {
e.printStackTrace();
}
以上的代碼可以簡化爲下面的代碼
InvocationHandler invocationHandler = new MyInvocationHandler();
Foo foo= (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[]{Foo.class},invocationHandler);
二、實踐操作
public interface Person {
void sleep();
}
public class Man implements Person {
@Override public void sleep() {
System.out.println("開始睡覺了");
}
}
public class LogUtil {
public void filter1(){
System.out.println("在代理對象的方法執行之前,進行攔截做點什麼");
}
public void filter2(){
System.out.println("在代理對象的方法執行之後,進行攔截做點什麼");
}
}
生成代理對象
public class MyProxyFactory {
public static Object getProxy(Object target){
MyInvocationHandler handler = new MyInvocationHandler();
handler.setTarget(target);
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),handler);
}
}
public class MyInvocationHandler implements InvocationHandler {
//需要被代理的對象
private Object target;
public void setTarget(Object target){
this.target=target;
}
//1.proxy代表動態代理的對象
//2.method代表正在執行的方法
//3.args代表調用目標方法時傳入的實參
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
LogUtil log = new LogUtil();
log.filter1();
//通過反射執行動態代理對象的所有方法
Object obj=method.invoke(target,args);
log.filter2();
return obj;
}
}
public static void main(String[] args){
Person target = new Man();
Person man= (Person) MyProxyFactory.getProxy(target);
man.sleep();
}
運行結果:
三、總結
一般普通編程無需用到動態代理,但在編寫框架或底層代碼時,它的作用就非常大了。還有就是使用動態代理可以非常靈活的實現解耦。
參考《瘋狂java講義》