靜態代理和動態代理主要解決的問題是:在直接訪問對象時帶來的問題,其目的就是為其他對象提供一個代理以控制對某個對象的訪問。代理類負責為委托類預處理消息,過濾消息並轉發消息,以及進行消息被委托類執行后的后續處理。
靜態代理在感覺上和裝飾設計模式很像
1)、在代理類中實現被代理類實現的所有接口,這樣保證了被代理類所能實現的方法,代理類也能實現,保證了兩邊行為的一致性,代理類就能轉型為被代理類,當作被代理類處理。而代理中有被代理類的對象,這樣,在代理類的內部實現接口方法時就能調用被代理類的方法,從而進行對被代理類的封裝。
簡單的示范:
package cn.edu.cjl; public interface Subject { public void replace(); }
package cn.edu.cjl; public class RealSubject implements Subject{ @Override public void replace() { // TODO Auto-generated method stub System.out.println("real subject..."); } }
package cn.edu.cjl; public class daili implements Subject { RealSubject subject; @Override public void replace() { System.out.println("before..."); if(subject==null){ subject=new RealSubject(); } subject.replace(); System.out.println("after..."); } }
package cn.edu.cjl; public class Client { public static void main(String[] args) { Subject subject=new daili(); subject.replace(); } }
代碼中定義接口Subject,真實的實現類是RealSubject,但是在在主方法中調用的是daili類,在daili類中同樣實現了Subject接口,但是真實上調用的是RealSubject類的方法。這就是靜態代理。
靜態代理可以解決直接訪問類方法帶來的問題,但是本身也有問題,就是當大量的使用靜態代理時類的個數將雙倍的增加,不利於程序的管理。
動態代理使用了反射技術,一個代理類可以為任意類提供代理。
代理類必須實現InvocationHandler接口,
對代理實例調用方法時,將對方法調用進行編碼並將其指派到它的代理程序的 invoke
方法。
invoke方法運用反射技術,通過java.lang.reflect.Proxy類中提供的靜態方法 newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
返回一個指定接口的代理類實例,該接口可以將方法調用指派到指定的調用處理程序,也就是代理類實現的InvocationHandler接口中的invoke方法中,這個方法的各個參數的意思是
ClassLoader loader:類加載器,定義代理類的類加載器,可以任意指定。
Class<?>[] interfaces: 被代理類所實現的所有接口的class數組,可以用class對象的getInterfaces()方法得到。
InvocationHandler h:實現了InvocationHandler接口的對象。
簡單的事例:
package cn.edu.cjl.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class proxy implements InvocationHandler { private Object object; public proxy(Object obj){ this.object=obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before"); Object resultObject= method.invoke(object, args); System.out.println("after"); return resultObject; } }
package cn.edu.cjl.proxy; import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) { Subject subject = null; RealSubject rSubject = new RealSubject(); proxy proxy = new proxy(rSubject); subject = (Subject) Proxy.newProxyInstance(Client.class .getClassLoader(), rSubject.getClass().getInterfaces(), proxy); subject.replace(); } }