代理模式(Proxy)是經過代理對象訪問目標對象,這樣能夠在目標對象基礎上加強額外的功能,如添加權限,訪問控制和審計等功能。
- 靜態代理
請參考下面的代碼:java
/** *聲明一個明星接口,明星只須要關注本身的唱、跳 */ public interface StarService { void sing(); void jump(); }
/** *明星接口的具體實現類 */ public class StarServiceImpl implements StarService{ public void sing() { System.out.println(" sing a song "); } public void jump() { System.out.println(" just dance "); } }
/** *代理類 */ public class StarServiceProxy implements StarService { private StarService starService; // 經過構造方法將目標實現類注入 public StarServiceProxy(StarService starService) { this.starService = starService; } public void sing() { System.out.println("唱歌以前先聯繫綜藝節目,肯定時間、地點"); starService.sing(); System.out.println("表演結束以後,安排下一場演出"); } public void jump() { return starService.jump(); System.out.println("跳舞以後,觀衆鼓掌"); } }
public class ProxyTest { public static void main(String[] args) { StarService starService = new StarServiceImpl(); StarServiceProxy proxy = new StarServiceProxy(starService); proxy.sing(); } }
輸出: 唱歌以前先聯繫綜藝節目,肯定時間、地點 sing a song 表演結束以後,安排下一場演出
總結:ide
- 靜態代理模式在不改變目標對象的前提下,實現了對目標對象的功能擴展;
- 不足: 靜態代理實現了目標對象的全部方法,一旦目標接口增長方法,代理對象和目標對象都要進行相應的修改,增長維護成本。
- 動態代理
Java中的動態代理須要java.lang.reflect.InvocationHandler
接口和 java.lang.reflect.Proxy
類的支持 。jdk
的動態代理是面向接口的,即jdk
的動態代理只能代理實現接口的類,不能代理抽象類或者沒有實現接口的類。函數
java.lang.reflect.InvocationHandler
接口的定義以下:工具
/** * Object proxy 被代理的對象 * Method method 要調用的方法 * Object[] args 方法調用時所須要參數 */ public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
java.lang.reflect.Proxy
類的定義以下:測試
/** * CLassLoader loader 類的加載器 * Class<?> interfaces 獲得所有的接口 * InvocationHandler h 獲得InvocationHandler接口的子類的實例 */ public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
jdk
動態代理流程:this
InvocationHandler
接口建立本身的調用處理器; ClassLoader
對象和一組interface
來建立動態代理類;// 自定義中間代理類 public class YourHandler implements InvocationHandler { // 目標對象 private Object targetObject; public ProxyHandler( Object proxied ) { this.proxied = proxied; } /*proxy表示代理目標對象,method表示原對象被調用的方法,args表示方法的參數*/ @Ovrride public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable { //在轉調具體目標對象以前,能夠執行一些功能處理 //轉調具體目標對象的方法 return method.invoke( proxy, args); //在轉調具體目標對象以後,能夠執行一些功能處理 } }
實際應用時代碼以下:代理
// RealSubject 要代理的目標對象 RealSubject real = new RealSubject(); // Subject 目標對象實現的接口 Subject proxySubject = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(), new Class[]{Subject.class}, new YourHandler(real)); // proxySubject 爲中間代理類 proxySubject.method( Object[] args);
Cglib
代理
`Cglib`代理補充了`jdk`中只面向接口進行代理的不足,`Cglib`代理支持基於對象代理,不用關心該對象是否實現了某個接口。 `Cglib`是一個`java`字節碼的生成工具,它動態生成一個被代理類的子類,子類重寫被代理的類的全部不是`final`的方法。在子類中採用方法攔截的技術攔截全部父類方法的調用,順勢織入橫切邏輯。 以上面的`StarServiceImpl`爲被代理對象,舉個例子:
/** * 自定義中間代理類 */ public class MyMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { // TODO Auto-generated method stub System.out.println("Before: " + method.getName()); Object object = methodProxy.invokeSuper(o, objects); System.out.println("After: " + method.getName()); return object; } }
// 測試以下 public static void main(String[] args) { Enhancer enhancer = new Enhancer(); //繼承被代理類 enhancer.setSuperclass(Star.class); //設置回調 enhancer.setCallback(new MyMethodInterceptor()); //設置代理類對象 StarServiceImpl starService = (StarServiceImpl) enhancer.create(); //在調用代理類中方法時會被咱們實現的方法攔截器進行攔截 starService.sing(); }
輸出結果以下: Before: sing sing a song After: sing