動態代理的用途:java
動態代理的用途與裝飾模式很類似,就是爲了對某個對象進行加強。全部使用裝飾者模式的案例均可以使用動態代理來替換,動態代理能夠更好的解耦合ide
加強有3個手段
1. 繼承
被加強對象不能變
加強內容不能變
2. 裝飾者模式
被加強對象可變
但加強內容不能變
3. 動態代理
被加強對象可變
加強內容也可變測試
如何實現動態代理?this
定義一個接口Interface, 被加強的對象的類都會實現這個接口spa
public interface Interface { public void fun(); }
實現這個Interface接口:
而這個InterfaceImpl就是動態代理中被加強的內容代理
public class InterfaceImpl implements Interface { @Override public void fun() { System.out.println("目標方法調用"); } }
定義一個接口Advice, 加強內容的類都會實現這個接口
這個接口有兩個未實現的方法:
before()前置加強的方法
after()後置加強的方法code
public interface Advice { public void before(); public void after(); }
而實現了Advice接口的對象就是動態代理中加強內容對象
JavaAPI:繼承
java.lang.reflect.Proxy接口
Object proxyObject = Proxy.newProxyInstance(ClassLoader classLoader, Class[] interfaces, InvocationHandler h);
返回一個指定接口的代理類實例,該接口能夠將方法調用指派到指定的調用處理程序
參數:
classLoader - 定義代理類的類加載器
interfaces - 代理類要實現的接口列表
h - 指派方法調用的調用處理程序
返回:
一個帶有代理類的指定調用處理程序的代理實例,它由指定的類加載器定義,並實現指定的接口
java.lang.reflect.InvocationHandler
public Object invoke(Object proxy, Method method, Object[] args);
這個invoke()方法在調用代理對象所實現接口中的方法時調用
* Object proxy:當前對象,即代理對象!在調用誰的方法!
* Method method:當前被調用的方法(目標方法)
* Object[] args:目標方法參數
調用proxy實例的方法時, 都會被InvocationHandler所捕獲, 所以只要實現InvocationHandler實現類的invoke()方法, 就能夠實現目標方法的加強
定義一個類ProxyFactory
該類經過兩個參數的public ProxyFactory(target,advice)構造方法構造ProxyFactory實例, 而後經過該實例的getProxy()方法獲得代理對象
public class ProxyFactory { private Object target; // 目標對象 private Advice advice; // 加強對象 public ProxyFactory(Object target, Advice advice) { this.target = target; this.advice = advice; } /** * 獲得代理對象 */ public Object getProxy() { return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 執行前置加強 advice.before(); // 執行目標對象的目標方法, 用result接收返回值 Object result = method.invoke(target, args); // 執行後置加強 advice.after(); // 返回目標方法的返回值result return result; } }); } }
測試動態代理
public static void main(String[] args) { InterfaceImpl target = new InterfaceImpl(); // 實現一個Advice的實例對象, 這個對象就是動態代理中加強內容 Advice advice = new Advice() { @Override public void before() { System.out.println("目標方法調用以前, 執行前置加強"); } @Override public void after() { System.out.println("目標方法調用以後, 執行後置加強"); } }; ProxyFactory proxyFactory = new ProxyFactory(target, advice); Interface proxy = (Interface) proxyFactory.getProxy(); proxy.fun(); }
Console輸出:
方法調用以前, 執行前置加強目標方法調用方法調用以後, 執行後置加強