動態代理屬於Java反射的一種。
當我們得到一個對象,想動態的為其一些方法每次被調用前后追加一些操作時,我們將會用到java動態代理。
下邊上代碼:
首先定義一個接口:
package com.liuyx; public interface Itf { public abstract void printMe(); public abstract void printSth(String me); }
接着是它的實現:
package com.liuyx; public class Cls implements Itf { @Override public void printMe() { System.out.println("I'm Cls!"); } @Override public void printSth(String str) { System.out.println(str); } }
我們的目的就是通過動態代理技術,在Cls這個類的對象的兩個方法執行前后,加上一些打印操作。
現在我們實現一個InvocationHandler,把我們想要通過代理者給被代理者追加的操作都寫在invoke方法里面:
package com.liuyx; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class StandardInvocation implements InvocationHandler { private Object obj; StandardInvocation(Object obj){ this.obj=obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before method excute!"); Object result = method.invoke(obj, args); System.out.println("after method excute!"); return result; } }
首先、這里面有一個obj,這個obj是必須的,我們既然要做代理,我們必須知道我們是給誰做代理,這里的obj就是被代理者。
動態代理說到底也是代理,代理模式里就要求有一個被代理者。
然后是invoke的三個參數、第一個參數就是代理者,如果你想對代理者做一些操作可以使用這個參數;第二個就是被執行的方法,第三個是執行該方法所需的參數。
當你執行代理者的某個方法的時候,最后跑的都是invoke方法。
然后是用法:
public static void main(String[] args) { //創建一個被代理者 Cls c = new Cls(); //創建一個InvocationHandler,描述我們希望代理者執行哪些操作 InvocationHandler i = new StandardInvocation(c); //通過剛才創建的InvocationHandler,創建真正的代理者。第一個參數是類加載器,第二個參數是這個代理者實現哪些接口 Itf pxy = (Itf) Proxy.newProxyInstance(Cls.class.getClassLoader(), new Class[] { Itf.class }, i); pxy.printSth("Hi"); }
pxy就是c的代理者。
最后來一個稍微改進的寫法:
package com.liuyx; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class InvocationHandlerTest implements InvocationHandler { private Object target; Object bind(Object i) { target = i; Object warpedItf; warpedItf = Proxy.newProxyInstance(target.getClass().getClassLoader(), i.getClass().getInterfaces(), this); return warpedItf; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before method excute!"); method.invoke(target, args); System.out.println("after method excute!"); return null; } public static void main(String[] args) { Cls c = new Cls(); InvocationHandlerTest pxy = new InvocationHandlerTest(); Itf itf = (Itf)pxy.bind(c); itf.printSth("Hello"); } }
java動態代理有一定局限性,需要定義至少一個接口,使用cglib則不必如此。