Java的反射框架提供了動態代理(Dynamic Proxy)機制,允許在運行期對目標類生成代理,避免重複開發。我們知道一個靜態代理是通過代理主題角色(Proxy)和具體主題角色(Real Subject)共同實現抽像主題角色(Subject)的邏輯的,只是代理主題角色把相關的執行邏輯委託給了具體主題角色而已,一個簡單的靜態代理如下所示:
//抽像主題角色
interface Subject{
//定義一個方法
public void request();
}
//具體主題角色
class RealSubject implements Subject{
//實現方法
public void request(){
//業務邏輯處理
}
}
//代理主題角色
class Proxy implements Subject{
//要代理哪個實現類
private Subject subject=null;
//默認被代理者
public Proxy(){
subject=new RealSubject();
}
//通過構造函數傳遞被代理者
public Proxy(Subject_subject){
subject=_subject;
}
//實現接口中定義的方法
public void request(){
before();
subject.request();
after();
}
//預處理
private void before(){
//do something
}
//善後處理
private void after(){
//do something
}
}
這是一個簡單的靜態代理。Java還提供了java.lang.reflect.Proxy用於實現動態代理:只要提供一個抽像主題角色和具體主題角色,就可以動態實現其邏輯的,其示例代碼如下:
//抽像主題角色
interface Subject{
//定義一個方法
public void request();
}
//具體主題角色
class RealSubject implements Subject{
//實現方法
public void request(){
//業務邏輯處理
}
}
class SubjectHandler implements InvocationHandler{
//被代理的對象
private Subject subject;
public SubjectHandler(Subject_subject){
subject=_subject;
}
//委託處理方法
public Object invoke(Object proxy, Method method, Objectargs)
throws Throwable{
//預處理
System.out.println("預處理");
//直接調用被代理類的方法
Object obj=method.invoke(subject, args);
//後處理
System.out.println("後處理");
return obj;
}
}
注意看,這裡沒有了代理主題角色,取而代之的是SubjectHandler作為主要的邏輯委託處理,其中invoke方法是接口InvocationHandler定義必須實現的,它完成了對真實方法的調用。
我們來詳細瞭解一下InvocationHanlder接口,動態代理是根據被代理的接口生成所有方法的,也就是說給定一個(或多個)接口,動態代理會宣稱「我已經實現該接口下的所有方法了」,那各位讀者想想看,動態代理怎麼才能實現代理接口中的方法呢?在默認情況下所有方法的返回值都是空的,是的,雖然代理已經實現了它,但是沒有任何的邏輯含義,那怎麼辦?好辦,通過InvocationHandler接口的實現類來實現,所有方法都是由該Handler進行處理的,即所有被代理的方法都由InvocationHandler接管實際的處理任務。
我們接著來看動態代理的場景類,代碼如下:
public static void main(Stringargs){
//具體主題角色,也就是被代理類
Subject subject=new RealSubject();
//代理實例的處理Handler
InvocationHandler handler=new SubjectHandler(subject);
//當前加載器
ClassLoader cl=subject.getClass().getClassLoader();
//動態代理
Subject proxy=(Subject)Proxy.newProxyInstance(cl, subject.getClass().
getInterfaces(),handler);
//執行具體主題角色方法
proxy.request();
}
此時就實現了不用顯式創建代理類即實現代理的功能,例如可以在被代理角色執行前進行權限判斷,或者執行後進行數據校驗。
動態代理很容易實現通用的代理類,只要在InvocationHandler的invoke方法中讀取持久化數據即可實現,而且還能實現動態切入的效果,這也是AOP(Aspect Oriented Programming)編程理念。