您好,登錄后才能下訂單哦!
小編給大家分享一下Java代理模式的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
具體如下:
即Proxy Pattern,23種java常用設計模式之一。代理模式的定義:對其他對象提供一種代理以控制對這個對象的訪問。
Java的代理模式是Java中比較常用的設計模式,分為2中代理:靜態代理與動態代理(JDK動態代理和cglib動態代理)
優點:
職責清晰 真實角色只需關注業務邏輯的實現,非業務邏輯部分,后期通過代理類完成即可。
高擴展性 不管真實角色如何變化,由于接口是固定的,代理類無需做任何改動。
缺點:
很明顯的一點就是反射機制,沒有高安全性,性能也相對來講低一些。
代理模式這種設計模式是一種使用代理對象來執行目標對象的方法并在代理對象中增強目標對象方法的一種設計模式。代理對象代為執行目標對象的方法,并在此基礎上進行相應的擴展。看起來是有點拗口,首先介紹一個原則:開閉原則(對擴展開放,對修改關閉)。一種好的設計模式甚至是架構,都是在不修改原有形態的基礎上擴展出新的功能。
事例場景:
小張是一個普普通通的碼農,每天勤勤懇懇地碼代碼。某天中午小張剛要去吃飯,一個電話打到了他的手機上。“是XX公司的小張嗎?我是YY公司的王AA”。“哦,是王總啊,有什么事情嗎?”。溝通過后,小張弄明白了,原來客戶有個需求,剛好負責這方面開發的是小張,客戶就直接找到了他。不過小張卻沒有答應客戶的請求,而是讓客戶找產品經理小李溝通。
是小張著急去吃面而甩鍋嗎?并不是,只是為了使故事可以套到代理模式上。我們先看一下代理模式的定義: * 為其他對象提供一種代理,以控制對這個對象的訪問。(Provide a surrogate or placeholder for another object to control access to it)
對照定義,碼農小張可以映射為其他對象,產品經理小李為小張的代理。我們通過JAVA代碼,表述上面事例。
一、靜態代理
什么是靜態代理:靜態代理就是在程序運行前就已經確定代理類與代理對象的代理模式
靜態代理模式就是如上圖所示,構造三個類實現他們的關系。
首先會思考的一點就是為什么需要實現同一個接口,如果不實現同一個接口,一樣可以“代理”功能,所以為什么非要實現同一個接口。我個人認為不實現統一接口的話應該叫做聚合而不是代理;然后,實現統一接口能夠使代理類與被代理類之間的聯系,提高代碼的復用性又能解耦。
package staticProxy; /** *接口 */ public interface DAOInterface { public void add(); public void delete(); public void update(); public void query(); }
package staticProxy; /** *被代理類 */ public class UserDao implements DAOInterface{ @Override public void add() { System.out.println("在目標對象中執行add"); } @Override public void delete() { System.out.println("在目標對象中執行delete"); } @Override public void update() { System.out.println("在目標對象中執行update"); } @Override public void query() { System.out.println("在目標對象中執行query"); } }
package staticProxy; /** * 代理類 * */ public class UserDaoProxy implements DAOInterface{ UserDao userDao = null; public UserDaoProxy(UserDao userDao){ this.userDao = userDao; } @Override public void add() { userDao.add(); System.out.println("記錄日志add"); } @Override public void delete() { userDao.delete(); System.out.println("記錄日志delete"); } @Override public void update() { userDao.update(); System.out.println("記錄日志update"); } @Override public void query() { userDao.query(); System.out.println("記錄日志query"); } }
靜態代理就是寫死了在代理對象中執行這個方法前后執行添加功能的形式,每次要在接口中添加一個新方法,則需要在目標對象中實現這個方法,并且在代理對象中實現相應的代理方法;利用Java的反射機制,動態的調用生成代理對象,就能完成動態代理的需求。
二、動態代理
1、JDK動態代理
在代理類管理器的新建代理實例方法中,必須要獲得類的加載器、類所實現的接口、還有一個攔截方法的句柄。
在句柄的invoke中如果不調用method.invoke則方法不會執行。在invoke前后添加通知,就是對原有類進行功能擴展了。創建好代理對象之后,proxy可以調用接口中定義的所有方法,因為它們實現了同一個接口,并且接口的方法實現類的加載器已經被反射框架獲取到了。
package JDKAgency; /** * DAO接口 */ public interface DAO { void add(); void update(); void delete(); void query(); }
package JDKAgency; /** * DAO的實現類 */ public class DAOImpl implements DAO { @Override public void add() { System.out.println("添加的方法"); } @Override public void update() { System.out.println("更新的方法"); } @Override public void delete() { System.out.println("刪除的方法"); } @Override public void query() { System.out.println("查詢的方法"); } }
package JDKAgency; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 代理類管理器 */ public class ProxyManager implements InvocationHandler {//動態代理的核心處理器接口 private Object object; public ProxyManager(Object object) { this.object = object; } public Object createNewInstance() { Object o = Proxy.newProxyInstance(object.getClass().getClassLoader(),//真實對象的類加載器 object.getClass().getInterfaces(),//真實對象的所有接口 this);//代理對象 return o; } @Override //代理對象 執行業務的方法 參數 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before......權限檢測");//前置通知 Object invoke = method.invoke(object, args);//動態調用執行方法 System.out.println("after......日志監控");//后置通知 return invoke; } }
package JDKAgency; /** * 測試 */ public class JTest { public static void main(String[] args) { //創建真實對象 DAO dao = new DAOImpl(); DAO o =(DAO) manager.createNewInstance(); //JDK動態代理是代理的接口,因此強制轉換應該轉換為接口,而不是實現類,若強制轉換實現類就會拋出ClassCastException,好比ArrayList與LinkedList實現統一接口List,兩者也不能相互轉換,但都可以向上轉型。 o.add(); o.query(); } }
注意:JDK動態代理是代理的接口,因此強制轉換應該轉換為接口,而不是實現類,若強制轉換實現類就會拋出ClassCastException,好比ArrayList與LinkedList實現統一接口List,兩者也不能相互轉換,但都可以向上轉型。
補充:
JavaJDK動態代理報錯java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to *。
javaJDK動態代理是Java原生代理模式。
注意:JDK動態代理是代理的接口,因此強制轉換應該轉換為接口,而不是實現類,若強制轉換實現類就會拋出ClassCastException,好比ArrayList與LinkedList實現統一接口List,兩者也不能相互轉換,但都可以向上轉型。
正確的轉型方案:
//創建處理器對象 ProxyManager manager = new ProxyManager(dao); //生成動態代理對象 // DAO o = (DAO) Proxy.newProxyInstance(dao.getClass().getClassLoader(), dao.getClass().getInterfaces(), manager);
2、cglib動態代理
cglib動態代理是web應用框架常用的一種動態代理方式。cglib是動態生成被代理類的子類,注意:是子類。
他需要先引入asm與cglib的jar包。如下圖:
接著廢話不多說,看代碼分析:
package CGlibAgency; /** * 被代理類 */ public class User { public void saveUser(){ System.out.println("保存對象。"); } public void updateUser(){ System.out.println("修改對象。"); } }
package CGlibAgency; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * 代理類管理器 */ public class Interceptor implements MethodInterceptor {//cgLib需要實現MethodInterceptor接口,cgLib是基于類的,動態的生成代理類(被代理類的子類) private Enhancer enhancer = new Enhancer();//Enhancer是Cglib代理的重要對象 public Object createProxy(Class superClass){ enhancer.setSuperclass(superClass);//獲取父類的Class enhancer.setCallback(this);//設置方法的回調,類似于JDK動態代理中的Proxy與InvocationHandler實現類的綁定回調 return enhancer.create();//返回代理類的對象 } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("'權限驗證'"); Object aSuper = methodProxy.invokeSuper(o, objects);//通過虛擬的代理對象的代理方法調用父類的方法,參數中一個是父類,一個是所有的子類對象數組(??) System.out.println("'日志收集'"); return aSuper; } }
package CGlibAgency; /** * 測試類 */ public class JTest { public static void main(String[] args) { Interceptor interceptor = new Interceptor();//創建代理管理對象 Object proxy = interceptor.createProxy(User.class);//創建一個代理類 System.out.println(User.class.getTypeName());//查看代理類的類型 User user = (User) proxy;//轉型,子類自動向上轉型 user.saveUser(); user.updateUser(); } }
以上是“Java代理模式的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。