您好,登錄后才能下訂單哦!
這篇文章主要介紹“Java代理模式與動態代理之間的關系是什么”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“Java代理模式與動態代理之間的關系是什么”文章能幫助大家解決問題。
代理模式是開發中常見的一種設計模式,使用代理模式可以很好的對程序進行橫向擴展。代理,顧名思義就是一個真實對象會存在一個代理對象,并且代理對象可以替真實對象完成相應操作,外部通過代理對象來訪問真實對象并且還可以在代理對象中進行額外操作的擴展。
代理模式的特征是擁有接口、代理類、被代理類。并且代理類與被代理類同時實現該接口。代理類與被代理類之間通常存在一定關聯,設計時會在代理類中注冊一個被代理類的對象用于調用代理類的方法。這也印證了代理對象依然是執行的真實對象的方法
代理模式又分為靜態代理和動態代理
靜態代理,關鍵字靜態是指在程序運行之前編譯時就已經確定了代理類、被代理類、接口。
下面列舉兩個示例展示靜態代理:
學生通過班長交班費,班長作為學生的代理,學生是被代理,具有同一行為就是交班費,這個行為我們用接口進行約束
程序:
// 接口 public interface Person {void giveMoney();} // 學生類--> 被代理類 public class Student implements Person{ private String name; public Student(String name) {this.name = name;} public void giveMoney() { System.out.println(name+"同學上交50元班費"); } } // 學生代理類 public class StuProxy implements Person{ private Student stu; public StuProxy(Student stu) { if (stu.getClass() == Student.class) { this.stu = stu; } } public void giveMoney() {stu.giveMoney();} }
測試:
public static void main(String[] args) { // 獲取學生實例 Student stu = new Student("張三"); // 學生找交錢給班長 學生找到代理 StuProxy stuProxy = new StuProxy(stu); // 班長交給老師 代理交錢(交的是學生的錢) stuProxy.giveMoney(); }
房屋租賃,租客通過中介找房源,租客為被代理類,中介為代理類,接口聲明租房方法
// 接口 public interface Rent {void doRent();} // 被代理類 public class Renter implements Rent{ public void doRent() { System.out.println("租客租房了"); } } // 代理類 public class RentProxy implements Rent{ private Renter renter; public RentProxy(Renter renter) { if (renter.getClass()==Renter.class) this.renter = renter; } public void doRent() {renter.doRent();} }
測試:
public static void main(String[] args) { // 創建租客 Renter renter = new Renter(); // 租客找到中介 RentProxy rentProxy = new RentProxy(renter); // 租客租房 rentProxy.doRent(); }
上述兩個示例,向代理類中注入被代理對象的方式都是通過構造器注入,當然也可以通過set方法注入
下面演示如果需要在已經編寫好的代理類的輸出中添加其他操作時的操作比如打印一個日志,在不修改源代碼的情況下擴展
// 下面是最經典的Service層的寫法 public interface UserService { void del(); void select(); } public class UserServiceImpl implements UserService{ public void del() { System.out.println("刪除操作"); } public void select() { System.out.println("查詢操作"); } }
假設現在我們需要在每一次執行操作前后打印一次執行日志,并且不能修改源代碼那么就可以用到代理模式,將UserServiceImpl作為被代理類,擴展代理類如下:
public class UserServiceImplProxy implements UserService{ private UserServiceImpl userService; // set注入 public void setUserService(UserServiceImpl userService) { this.userService = userService; } public void del() { printLog(); userService.del(); } public void select() { printLog(); userService.select(); } private void printLog(){ System.out.println("執行時間="+new Date()); } }
動態代理:代理類在程序運行時被創建的代理方式。
關鍵在于動態,程序具有了動態特性,可以在運行期間根據不同的目標對象生成動態代理對象,并且可以通過動態代理對象對目標對象(真實對象)進行功能性補強。大白話來講就是,可以在程序運行期間額外的對真實對象功能進行擴展。
此處的動態代理對象不是通過預先編寫好的程序生成的,而是運行期間由于用戶需求或者說是代碼的指示生成的
動態代理分為兩種:一類是基于接口實現的動態代理,另一類是基于類的動態代理
基于接口的動態代理–JDK動態代理通過反射完成,基于類實現的–>cglib
JDK動態代理核心:Proxy類、InvocationHandler接口、要參與代理的目標類必須實現對應接口,比如上述的Student必須實現Person接口。
繼續以上述學生交班費為例,更改為動態代理模式:
JDK動態代理中間類:該類需要實現InvocationHandler接口
// JDK動態代理中間類 public class ProxyInvocationHandler implements InvocationHandler { // 被代理的對象 private Object target; // ser方法注入參數 public void setTarget(Object target) {this.target = target;} // 生成動態代理類 public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this); } // 處理代理實例,并返回結果 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = method.invoke(target,args); return result; } }
測試:
public static void main(String[] args) { // 獲取真實角色 Student stu = new Student("張三三"); // 動態代理中間類對象 InvocationHandlerProxyStudent proxyStudent = new InvocationHandlerProxyStudent(); proxyStudent.setStu(stu); // 代理類實例 Person proxy = (Person) proxyStudent.getProxy(); // 代理類實例調用方法 proxy.giveMoney(); }
上述程序,我們利用Proxy來生成代理類:
public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(), stu.getClass().getInterfaces(),this); }
Proxy提供了靜態的獲取Proxy代理類的方法newProxyInstance
,三個參數分別是1.類加載器 2.代理對象實現的接口 3. 調用處理程序(InvocationHandler)
在InvocationHandler官方文檔就已經指出,每一個代理實例都關聯有一個InvocationHandler調用處理程序,所以這里填this即可
在使用代理類的時候首先我們創建需要被代理的真實對象和動態代理中間類的對象,用set方法將真實對象交給中間類中的代理對象。在調用上述getProxy方法獲取代理類。動態代理相對于靜態代理有些難以理解,這是因為靜態代理的代理類可以在程序中顯式的被看到,而動態代理中的代理類文件是緩存在Java虛擬機,類名叫$Proxy0。
在虛擬機中生成的代理類中就會將我們所調用的方法內置,我們在執行proxy.giveMoney()
的同時,實際上是將giveMoney()方法作為參數傳進invoke()的參數中去,而此時我們就可以將其他的操作交給invoke,由于所有代理對象在執行時最終都會走invoke方法,所以也為我們的開發節省大量代碼
關于“Java代理模式與動態代理之間的關系是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。