您好,登錄后才能下訂單哦!
java中的代理是什么?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
代理是一種設計模式,提供了對目標對象另外的訪問方式,即通過代理對象訪問目標對象。可以不修改目標對象,對目標對象功能進行拓展。
代理的作用:降低代碼的冗余。
代理模式的實現分為兩大類:靜態實現和動態實現,動態實現根據實現的方式分為:jdk 動態實現,cglib動態實現
Java的三種代理模式
想要實現以上的需求有三種方式,這一部分我們只看三種模式的代碼怎么寫,先不涉及實現原理的部分。
1、靜態代理
public interface ISinger { void sing(); } /** * 目標對象實現了某一接口 */ public class Singer implements ISinger{ public void sing(){ System.out.println("唱一首歌"); } } /** * 代理對象和目標對象實現相同的接口 */ public class SingerProxy implements ISinger{ // 接收目標對象,以便調用sing方法 private ISinger target; public UserDaoProxy(ISinger target){ this.target=target; } // 對目標對象的sing方法進行功能擴展 public void sing() { System.out.println("向觀眾問好"); target.sing(); System.out.println("謝謝大家"); } }
測試
/** * 測試類 */ public class Test { public static void main(String[] args) { //目標對象 ISinger target = new Singer(); //代理對象 ISinger proxy = new SingerProxy(target); //執行的是代理的方法 proxy.sing(); } }
優點: 做到不修改目標對象的功能前提下,對目標功能擴展
缺點:這種實現方式很直觀也很簡單,但其缺點是代理對象必須提前寫出,如果接口層發生了變化,代理對象的代碼也要進行維護。如果能在運行時動態地寫出代理對象,不但減少了一大批代理類的代碼,也少了不斷維護的煩惱,不過運行時的效率必定受到影響。這種方式就是接下來的動態代理。
2、JDK代理
跟靜態代理的前提一樣,依然是對Singer對象進行擴展
public interface ISinger { void sing(); } /** * 目標對象實現了某一接口 */ public class Singer implements ISinger{ public void sing(){ System.out.println("唱一首歌"); } }
這回直接上測試,由于java底層封裝了實現細節(之后會詳細講),所以代碼非常簡單,格式也基本上固定。
調用Proxy類的靜態方法newProxyInstance即可,該方法會返回代理類對象
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )
接收的三個參數依次為:
● ClassLoader loader:指定當前目標對象使用類加載器,寫法固定
● Class<?>[] interfaces:目標對象實現的接口的類型,寫法固定
● InvocationHandler h:事件處理接口,需傳入一個實現類,一般直接使用匿名內部類
測試代碼
public class Test{ public static void main(String[] args) { Singer target = new Singer(); ISinger proxy = (ISinger) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("向觀眾問好"); //執行目標對象方法 Object returnValue = method.invoke(target, args); System.out.println("謝謝大家"); return returnValue; } }); proxy.sing(); } }
優點:動態實現了不改變目標對象邏輯的擴展
缺點:可以看出靜態代理和JDK代理有一個共同的缺點,就是目標對象必須實現一個或多個接口,不然無法實現動態代理。
3、Cglib代理
前提條件:
● 需要引入cglib的jar文件,由于Spring的核心包中已經包括了Cglib功能,所以也可以直接引入spring-core-3.2.5.jar
● 目標類不能為final
● 目標對象的方法如果為final/static,那么就不會被攔截,即不會執行目標對象額外的業務方法
/** * 目標對象,沒有實現任何接口 */ public class Singer{ public void sing() { System.out.println("唱一首歌"); } }
/** * Cglib子類代理工廠 */ public class ProxyFactory implements MethodInterceptor{ // 維護目標對象 private Object target; public ProxyFactory(Object target) { this.target = target; } // 給目標對象創建一個代理對象 public Object getProxyInstance(){ //1.工具類 Enhancer en = new Enhancer(); //2.設置父類 en.setSuperclass(target.getClass()); //3.設置回調函數 en.setCallback(this); //4.創建子類(代理對象) return en.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("向觀眾問好"); //執行目標對象的方法 Object returnValue = method.invoke(target, args); System.out.println("謝謝大家"); return returnValue; } }
這里的代碼也非常固定,只有標黃部分是需要自己寫出
測試
/** * 測試類 */ public class Test{ public static void main(String[] args){ //目標對象 Singer target = new Singer(); //代理對象 Singer proxy = (Singer)new ProxyFactory(target).getProxyInstance(); //執行代理對象的方法 proxy.sing(); } }
優點:動態實現了不改變目標對象邏輯的擴展
缺點:目標必須實現接口,不然無法實現動態代理
總結:三種代理模式各有優缺點和相應的適用范圍,主要看目標對象是否實現了接口。以Spring框架所選擇的代理模式舉例
在Spring的AOP編程中:
如果加入容器的目標對象有實現接口,用JDK代理
如果目標對象沒有實現接口,用Cglib代理
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。