摘要:動態代理又被稱為代理或接口代理。靜態代理在編譯時產生字節碼文件,可以直接使用,效率高。代理無需實現接口,通過生成類字節碼實現代理,比反射稍快,不存在性能問題,但會繼承目標對象,需要重寫方法,所以目標對象不能為類。
一、代理模式介紹
代理模式是一種設計模式,提供了對目標對象額外的訪問方式,即通過代理對象訪問目標對象,這樣可以在不修改原目標對象的前提下,提供額外的功能操作,擴展目標對象的功能。
簡言之,代理模式就是設置一個中間代理來控制訪問原目標對象,以達到增強原對象的功能和簡化訪問方式。
代理模式UML類圖
舉個例子,我們生活中經常到火車站去買車票,但是人一多的話,就會非常擁擠,于是就有了代售點,我們能從代售點買車票了。這其中就是代理模式的體現,代售點代理了火車站對象,提供購買車票的方法。
二、靜態代理這種代理方式需要代理對象和目標對象實現一樣的接口。
優點:可以在不修改目標對象的前提下擴展目標對象的功能。
缺點:
冗余。由于代理對象要實現與目標對象一致的接口,會產生過多的代理類。
不易維護。一旦接口增加方法,目標對象與代理對象都要進行修改。
舉例:保存用戶功能的靜態代理實現
接口類: IUserDao
package com.proxy; public interface IUserDao { public void save(); }
目標對象:UserDao
package com.proxy; public class UserDao implements IUserDao{ @Override public void save() { System.out.println("保存數據"); } }
靜態代理對象:UserDapProxy 需要實現IUserDao接口!
package com.proxy; public class UserDaoProxy implements IUserDao{ private IUserDao target; public UserDaoProxy(IUserDao target) { this.target = target; } @Override public void save() { System.out.println("開啟事務");//擴展了額外功能 target.save(); System.out.println("提交事務"); } }
測試類:TestProxy
package com.proxy; import org.junit.Test; public class StaticUserProxy { @Test public void testStaticProxy(){ //目標對象 IUserDao target = new UserDao(); //代理對象 UserDaoProxy proxy = new UserDaoProxy(target); proxy.save(); } }
輸出結果
開啟事務 保存數據 提交事務三、動態代理
動態代理利用了JDK API,動態地在內存中構建代理對象,從而實現對目標對象的代理功能。動態代理又被稱為JDK代理或接口代理。
靜態代理與動態代理的區別主要在:
靜態代理在編譯時就已經實現,編譯完成后代理類是一個實際的class文件
動態代理是在運行時動態生成的,即編譯完成后沒有實際的class文件,而是在運行時動態生成類字節碼,并加載到JVM中
特點:
動態代理對象不需要實現接口,但是要求目標對象必須實現接口,否則不能使用動態代理。
JDK中生成代理對象主要涉及的類有
java.lang.reflect Proxy,主要方法為
static Object newProxyInstance(ClassLoader loader, //指定當前目標對象使用類加載器 Class>[] interfaces, //目標對象實現的接口的類型 InvocationHandler h //事件處理器 ) //返回一個指定接口的代理類實例,該接口可以將方法調用指派到指定的調用處理程序。
java.lang.reflect InvocationHandler,主要方法為
Object invoke(Object proxy, Method method, Object[] args) // 在代理實例上處理方法調用并返回結果。
舉例:保存用戶功能的動態代理實現
接口類: IUserDao
package com.proxy; public interface IUserDao { public void save(); }
目標對象:UserDao
package com.proxy; public class UserDao implements IUserDao{ @Override public void save() { System.out.println("保存數據"); } }
動態代理對象:UserProxyFactory
package com.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyFactory { private Object target;// 維護一個目標對象 public ProxyFactory(Object target) { this.target = target; } // 為目標對象生成代理對象 public Object getProxyInstance() { return 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 null; } }); } }
測試類:TestProxy
package com.proxy; import org.junit.Test; public class TestProxy { @Test public void testDynamicProxy (){ IUserDao target = new UserDao(); System.out.println(target.getClass()); //輸出目標對象信息 IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance(); System.out.println(proxy.getClass()); //輸出代理對象信息 proxy.save(); //執行代理方法 } }
輸出結果
class com.proxy.UserDao class com.sun.proxy.$Proxy4 開啟事務 保存數據 提交事務四、cglib代理
cglib is a powerful, high performance and quality Code Generation Library. It can extend JAVA classes and implement interfaces at runtime.
cglib (Code Generation Library )是一個第三方代碼生成類庫,運行時在內存中動態生成一個子類對象從而實現對目標對象功能的擴展。
cglib特點
JDK的動態代理有一個限制,就是使用動態代理的對象必須實現一個或多個接口。
如果想代理沒有實現接口的類,就可以使用CGLIB實現。
CGLIB是一個強大的高性能的代碼生成包,它可以在運行期擴展Java類與實現Java接口。
它廣泛的被許多AOP的框架使用,例如Spring AOP和dynaop,為他們提供方法的interception(攔截)。
CGLIB包的底層是通過使用一個小而快的字節碼處理框架ASM,來轉換字節碼并生成新的類。
不鼓勵直接使用ASM,因為它需要你對JVM內部結構包括class文件的格式和指令集都很熟悉。
cglib與動態代理最大的區別就是
使用動態代理的對象必須實現一個或多個接口
使用cglib代理的對象則無需實現接口,達到代理類無侵入。
使用cglib需要引入cglib的jar包,如果你已經有spring-core的jar包,則無需引入,因為spring中包含了cglib。
cglib的Maven坐標
cglib cglib 3.2.5
舉例:保存用戶功能的動態代理實現
目標對象:UserDao
package com.cglib; public class UserDao{ public void save() { System.out.println("保存數據"); } }
代理對象:ProxyFactory
package com.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class ProxyFactory implements MethodInterceptor{ private Object target;//維護一個目標對象 public ProxyFactory(Object target) { this.target = target; } //為目標對象生成代理對象 public Object getProxyInstance() { //工具類 Enhancer en = new Enhancer(); //設置父類 en.setSuperclass(target.getClass()); //設置回調函數 en.setCallback(this); //創建子類對象代理 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 null; } }
測試類:TestProxy
package com.cglib; import org.junit.Test; public class TestProxy { @Test public void testCglibProxy(){ //目標對象 UserDao target = new UserDao(); System.out.println(target.getClass()); //代理對象 UserDao proxy = (UserDao) new ProxyFactory(target).getProxyInstance(); System.out.println(proxy.getClass()); //執行代理對象方法 proxy.save(); } }
輸出結果
class com.cglib.UserDao class com.cglib.UserDao$$EnhancerByCGLIB$$552188b6 開啟事務 保存數據 關閉事務五、總結
靜態代理實現較簡單,只要代理對象對目標對象進行包裝,即可實現增強功能,但靜態代理只能為一個目標對象服務,如果目標對象過多,則會產生很多代理類。
JDK動態代理需要目標對象實現業務接口,代理類只需實現InvocationHandler接口。
動態代理生成的類為 lass com.sun.proxy.$Proxy4,cglib代理生成的類為class com.cglib.UserDao$$EnhancerByCGLIB$$552188b6。
靜態代理在編譯時產生class字節碼文件,可以直接使用,效率高。
動態代理必須實現InvocationHandler接口,通過反射代理方法,比較消耗系統性能,但可以減少代理類的數量,使用更靈活。
cglib代理無需實現接口,通過生成類字節碼實現代理,比反射稍快,不存在性能問題,但cglib會繼承目標對象,需要重寫方法,所以目標對象不能為final類。
六、相關資料代理模式相關知識
代理模式及Java實現動態代理
設計模式讀書筆記 - 代理模式
JDK動態代理實現原理
Java 動態代理機制分析及擴展
Java代理(jdk靜態代理、動態代理和cglib動態代理)
AOP的底層實現-CGLIB動態代理和JDK動態代理
深入淺出CGlib-打造無入侵的類代理
Spring AOP 實現原理與 CGLIB 應用
UML相關知識
博客 - UML類圖與類的關系詳解
goole圖書 -《UML建模實例詳解》
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/70513.html
Java的三種代理模式 參考:http://www.cnblogs.com/cenyu/...Java核心技術原書第九版6.5節 為什么使用代理 我們在寫一個功能函數時,經常需要在其中寫入與功能不是直接相關但很有必要的代 碼,如日志記錄,信息發送,安全和事務支持等,這些枝節性代碼雖然是必要的,但它會帶來以下麻煩: 枝節性代碼游離在功能性代碼之外,它不是函數的目的,這是對OO是一種破壞 枝節性...
摘要:設計模式之代理模式今天學到的動態代理實現,對代理這個概念很模糊,看了一篇文章發現這是一種設計模式,于是學習記錄一下。簡介代理模式是一種對象結構型的模式,主要為其他對象提供一種代理以控制對這個對象的訪問。下面依次講解著三種代理。 設計模式之代理模式 今天學到Spring的動態代理實現AOP,對代理這個概念很模糊,看了一篇文章發現這是一種設計模式,于是學習記錄一下。 簡介 代理模式是一種對...
摘要:代理模式代理模式通俗一點的解釋就是在操作一個對象和對象中的方法時,不是直接操作這個對象,還是通過一個代理對象來操作這個實際的目標對象。 代理模式: 代理模式通俗一點的解釋就是在操作一個對象和對象中的方法時,不是直接操作這個對象,還是通過一個代理對象來操作這個實際的目標對象。應用場景一般是需要在執行某個已經寫好的方法前后再添加一段邏輯,比如執行方法前打印日志,或者在執行方法之前和之后打時...
摘要:代理模式的實現靜態代理優缺點優點只對對需要的方法加代理邏輯。通過繼承的方式進行代理,無論目標對象有沒有實現接口都可以代理,但是無法處理的情況。 注意:本文所有的class使用的static修飾主要是為了能在一個類里面測試。實際項目中不應該這樣做的,應該分包分class。文字描述不是很多,還是看代碼比較好理解吧... 1. Java代理的理解 代理模式是一種設計模式,簡單說即是在不改變源...
閱讀 3297·2021-11-16 11:45
閱讀 2655·2021-09-22 15:23
閱讀 564·2021-07-30 14:58
閱讀 459·2019-08-30 15:54
閱讀 2235·2019-08-29 16:19
閱讀 3016·2019-08-29 12:45
閱讀 935·2019-08-23 17:57
閱讀 1788·2019-08-23 17:54