IDB package com.bjpowernode.proxy; /** * 代理類和目標類都必須使用同一個介面。 */ public interface IDB { int insert(); int delete(); int update(); } OracleDB package com ...
IDB
package com.bjpowernode.proxy; /** * 代理類和目標類都必須使用同一個介面。 */ public interface IDB { int insert(); int delete(); int update(); }
OracleDB
package com.bjpowernode.proxy; /** * 這是一個Oracle資料庫相關的操作類 * * 目標類(委托類)。 */ public class OracleDB implements IDB{ public int insert(){ //以下是一個插入操作 System.out.println("Oracle insert data...."); try { Thread.sleep(526); } catch (InterruptedException e) { e.printStackTrace(); } return 0; } public int delete(){ //以下是一個刪除操作 System.out.println("Oracle delete data...."); try { Thread.sleep(569); } catch (InterruptedException e) { e.printStackTrace(); } return 0; } public int update(){ //以下是一個更新操作 System.out.println("Oracle update data...."); try { Thread.sleep(456); } catch (InterruptedException e) { e.printStackTrace(); } return 0; } }
TimeInvocationHandler
package com.bjpowernode.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * 註冊在這個介面中的代碼,在代理對象調用代理方法的時候,自動執行。 * 我們的擴展代碼就註冊在這個類中。 */ public class TimeInvocationHandler implements InvocationHandler { //這個程式運行期,obj引用中保存了記憶體地址指向的對象是一個目標對象。 private Object obj; public TimeInvocationHandler(Object obj){ this.obj = obj; } /** * proxy 是代理對象的引用。 * method 是目標類中的目標方法 * args 是目標類中的目標方法的實參 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long begin = System.currentTimeMillis(); //通過反射機制去調用目標類中的目標方法 Object retValue = method.invoke(obj, args); long end = System.currentTimeMillis(); System.out.println("方法執行所耗費" + (end-begin) + "毫秒"); return retValue; } }
Test
package com.bjpowernode.proxy; import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { //創建目標類對象 IDB db = new OracleDB(); //創建代理對象 //DBProxy dbProxy = new DBProxy(); //這是靜態代理模式中創建對象,因為DBProxy是我們程式員手動編寫的。 //創建代理對象(這次創建代理對象是交給JVM完成,包括在這個過程中,JVM也會自動生成“代理類的位元組碼”) //這個代理類是動態生成的位元組碼不會以.class文件的形式保存在硬碟上,所以我們稱作動態代理。 //第一個參數是類裝載器:JVM會在記憶體中自動生成一個位元組碼,但是這個位元組碼要想運行,必須經過類裝載器的裝載 //然後進一步解析,所以必須傳遞一個類裝載器,這個類裝載器就是用來裝載這個臨時的“位元組碼”。 //代理類和目標類必須使用同一個類裝載器。 //第二個參數:是JVM在生成代理類的時候需要實現介面,但是這個介面又不能隨便寫,因為代理類和目標類要求實現相同的介面。 //所以我們將目標類實現的介面獲取到之後傳遞過來就行了。 //JDK中提供的代理模式只能代理介面。如果目標類它的父類型不是一個介面而是一個抽象類,那麼JDK中提供的動態代理就不能用了,需要使用 //第三方組件,例如:cglib。 //第三個參數:是InvocationHandler,這是一個介面,這個介面中的方法會在代理類調用代理方法的時候自動執行。 IDB dbProxy = (IDB)Proxy.newProxyInstance(db.getClass().getClassLoader(), db.getClass().getInterfaces(), new TimeInvocationHandler(db)); //通過代理對象中的方法去執行目標對象中的方法。 dbProxy.insert(); //dbProxy是一個動態生成的代理對象,由於這個代理對象實現了和OracleDB一樣的介面,所以可以用IDB介面指向JVM中的代理對象。 dbProxy.delete(); // 這裡調用的delete方法是是代理類中的代理方法,不是目標類中的目標方法。但是一定會通過代理方法去調用目標方法。 dbProxy.update(); } }