神遊:
場景一:公司老闆比爾,祕書莫妮卡,任何外部電話都需要通過莫妮卡轉給比爾,莫妮卡可能會答覆你沒預約不能與比爾通話、比爾現在忙不方便跟你通話、請你稍等馬上幫你轉接等。這個場景類似靜態代理應用,莫妮卡是比爾的代理,任何事情找比爾都只能通過莫妮卡來轉接。
場景二:張三、李四、王五都想去旅遊,都去找中旅,張三想去臺灣,中旅就派一個臺灣導遊接待張三;李四想去泰國,中旅就派一個泰國導遊接待李四;王五想去新西蘭,中旅就派一個新西蘭導遊接待王五。這個場景類似動態代理應用,中旅類似動態代理。
代理模式:
代理模式的主要作用是爲其他對象提供一種代理以控制對這個對象的訪問。在某些情況下,一個對象不想或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用。代理模式的思想是爲了提供額外的處理或者不同的操作而在實際對象與調用者之間插入一個代理對象。這些額外的操作通常需要與實際對象進行通信。
代理模式在Java中表現爲代理類與委託類實現相同的接口(Interface),代理類主要負責爲委託類預處理消息、過濾消息、把消息轉發給委託類,以及事後處理消息等;而委託類纔則真正實現的接口業務邏輯;客戶類不能直接訪問委託類,而是通過訪問代理類來間接調用委託類。
Java動態代理:
Java靜態代理就是編譯期已經確定代理類,以及代理類中的處理邏輯;動態代理是在運行期運用Java反射機制臨時生成代理類,AspectJ實現的AOP就是典型的動態代理應用。Java開發類庫提供了InvocationHandler接口和Porxy類供我們使用動態代理模式。
java.lang.reflect.InvocationHandler接口:每個代理類都會綁定一個Invocation Handler,當代理類的方法被調用時,代理類就會調用handler的invoke方法進行處理。invoke方法中的參數proxy就是新生成代理類的instance,method參數是要調用的業務方法,args參數是業務方法參數。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
java.lang.reflect.Proxy類:動態生成的代理類的父類,提供newProxyInstance接口用於生成代理類並創建代理類instance;因爲新生成的類class文件需要ClassLoader加載,所以要傳入ClassLoader參數;因爲代理類需要實現業務接口,所以要傳入interfaces參數,這也是這種代理實現機制的特定或者說缺陷,即委託類一定要實現業務接口,定義業務接口是必要條件;因爲要綁定一個handler,所以要傳入h參數,或者說代理類需要調用handler的invoke方法。
/** * the invocation handler for this proxy instance. * @serial */ protected InvocationHandler h; @CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
二手房代理代碼示例:
package com.stevex.app.forkjoin; public interface SecondhandHouse { public int price(); } package com.stevex.app.forkjoin; public class Vanke implements SecondhandHouse { public int price() { return 1000000; } } package com.stevex.app.forkjoin; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ZhongyuanSecondHouse { public static void main(String[] args) { final SecondhandHouse sh = new Vanke(); SecondhandHouse proxy = (SecondhandHouse) Proxy.newProxyInstance(sh .getClass().getClassLoader(), sh.getClass().getInterfaces(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; System.out.println("簽訂看房合同"); result = method.invoke(sh, args); System.out.println("繳交定金"); return result; } }); System.out.println("改二手房價格爲:" + proxy.price()); } }