導航:首頁 > 編程語言 > java動態代理cglib

java動態代理cglib

發布時間:2022-09-12 04:13:09

java實現動態代理與cglib實現動態代理實現方式有什麼不同

一、背景在上一篇博客中(java動態代理:)提到,java的動態代理是必須基於介面的,而在編程中,使用到的外部類並不是基於介面編程的比比皆是,這有如何實現動態代理看使用可以基於類實現動態代理的CGLib!二、簡介CGLib(CodeGenerationLibrary)是一個強大、高性能的Code生成類庫,它可以在程序運行期間動態擴展類或介面;它的底層是使用java位元組碼操作框架ASM實現;三、使用CGLib核心類:1、net.sf.cglib.proxy.Enhancer:主要增強類,通過位元組碼技術動態創建委託類的子類實例;2、net.sf.cglib.proxy.MethodInterceptor:常用的方法攔截器介面,需要實現intercept方法,實現具體攔截處理

⑵ Spring的兩種代理JDK和CGLIB的區別淺談

一、原理區別
Java動態代理是利用反射機制生成一個實現代理介面的匿名類,在調用具體方法前調用InvokeHandler來處理。
而cglib動態代理是利用asm開源包,對代理對象類的class文件載入進來,通過修改其位元組碼生成子類來處理。
1、如果目標對象實現了介面,默認情況下會採用JDK的動態代理實現AOP
2、如果目標對象實現了介面,可以強制使用CGLIB實現AOP

3、如果目標對象沒有實現了介面,必須採用CGLIB庫,spring會自動在JDK動態代理和CGLIB之間轉換
如何強制使用CGLIB實現AOP?
(1)添加CGLIB庫,SPRING_HOME/cglib/*.jar
(2)在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>

JDK動態代理和CGLIB位元組碼生成的區別?
(1)JDK動態代理只能對實現了介面的類生成代理,而不能針對類
(2)CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法
因為是繼承,所以該類或方法最好不要聲明成final

二、代碼實現

[html] view plain
package com.fy.spring.proxy;

public interface UserManager {
public void addUser(String id, String password);
public void delUser(String id);
}

[html] view plain
package com.fy.spring.proxy;

public class UserManagerImpl implements UserManager {

public void addUser(String id, String password) {
System.out.println(".: 掉用了UserManagerImpl.addUser()方法! ");

}

public void delUser(String id) {
System.out.println(".: 掉用了UserManagerImpl.delUser()方法! ");

}
}
JDK動態代理類

[html] view plain
package com.fy.spring.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
*
* JDK動態代理類
*
*
*/
public class JDKProxy implements InvocationHandler {

private Object targetObject;//需要代理的目標對象

public Object newProxy(Object targetObject) {//將目標對象傳入進行代理
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);//返回代理對象
}

public Object invoke(Object proxy, Method method, Object[] args)//invoke方法
throws Throwable {
checkPopedom(); //一般我們進行邏輯處理的函數比如這個地方是模擬檢查許可權
Object ret = null; // 設置方法的返回值
ret = method.invoke(targetObject, args); //調用invoke方法,ret存儲該方法的返回值
return ret;
}

private void checkPopedom() {//模擬檢查許可權的例子
System.out.println(".:檢查許可權 checkPopedom()!");
}
}
CGLibProxy動態代理類

[html] view plain
package com.fy.spring.proxy;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
* CGLibProxy動態代理類的實例
*
*
*/
public class CGLibProxy implements MethodInterceptor {

private Object targetObject;// CGLib需要代理的目標對象

public Object createProxyObject(Object obj) {
this.targetObject = obj;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());
enhancer.setCallback(this);
Object proxyObj = enhancer.create();
return proxyObj;// 返回代理對象
}

public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
Object obj = null;
if ("addUser".equals(method.getName())) {// 過濾方法
checkPopedom();// 檢查許可權
}
obj = method.invoke(targetObject, args);
return obj;
}

private void checkPopedom() {
System.out.println(".:檢查許可權 checkPopedom()!");
}
}
測試類:

[html] view plain
public class Client {

public static void main(String[] args) {

UserManager userManager = (UserManager) new CGLibProxy()
.createProxyObject(new UserManagerImpl());
System.out.println("-----------CGLibProxy-------------");
userManager.addUser("tom", "root");
System.out.println("-----------JDKProxy-------------");
JDKProxy jdkPrpxy = new JDKProxy();
UserManager userManagerJDK = (UserManager) jdkPrpxy
.newProxy(new UserManagerImpl());
userManagerJDK.addUser("tom", "root");
}

}
運行結果:

[html] view plain
-----------CGLibProxy-------------
檢查許可權 checkPopedom()!
掉用了UserManagerImpl.addUser()方法!
-----------JDKProxy-------------
檢查許可權 checkPopedom()!
掉用了UserManagerImpl.addUser()方法!
三、區別
JDK代理是不需要依賴第三方的庫,只要JDK環境就可以進行代理,它有幾個要求
* 實現InvocationHandler
* 使用Proxy.newProxyInstance產生代理對象
* 被代理的對象必須要實現介面
使用JDK動態代理,目標類必須實現的某個介面,如果某個類沒有實現介面則不能生成代理對象。

CGLib 必須依賴於CGLib的類庫,Cglib原理是針對目標類生成一個子類,覆蓋其中的所有方法,所以目標類和方法不能聲明為final類型。針對介面編程的環境下推薦使用JDK的代理。從執行效率上看,Cglib動態代理效率較高。在Hibernate中的攔截器其實現考慮到不需要其他介面的條件Hibernate中的相關代理採用的是CGLib來執行。

⑶ java 我不理解動態代理的意義

人家是動態編程,需要在原來的方法的功能基礎上再添加一些功能,而不用改變這個方法的簽名,原來調用這個方法的類依然能正常工作。

比如,現在要把一段文本發送給另一個人,普通方法是 void send(File a),現在我們弄出個特性,就像 Spring AOP 那樣,在 send 之前給這個 a 壓縮一下。原來的程序沒有壓縮功能,現在我們需要添加的話而不改變原來所有的代碼的話就得用類似 AOP 這樣的代碼來處理。

一般一個無法再繼承的類和方法,要用代理,而能夠繼承的類和方法可以在內在中直接生成一個新的 java 類繼承它然後覆蓋掉那個 send 方法,像 hibernate/spring/jboss 都把這些自動完成了。
而像 AspectJ 這種 AOP 剛不同,它直接把人家的 class 代碼修改了,它就不需要使用代理。

這些在新的 JDK 6 中都可以通過 Instrument 來做到,不過也是個通用的方法,還得通過規則來定製什麼情況下處理,什麼時候不處理。

⑷ Spring的兩種代理JDK和CGLIB的區別淺談

原理區別:
java動態代理是利用反射機制生成一個實現代理介面的匿名類,在調用具體方法前調用InvokeHandler來處理。而cglib動態代理是利用asm開源包,對代理對象類的class文件載入進來,通過修改其位元組碼生成子類來處理。
1、如果目標對象實現了介面,默認情況下會採用JDK的動態代理實現AOP
2、如果目標對象實現了介面,可以強制使用CGLIB實現AOP
3、如果目標對象沒有實現了介面,必須採用CGLIB庫,spring會自動在JDK動態代理和CGLIB之間轉換

⑸ Spring 中JDKProxy和CGlibProxy的區別

java動態代理是利用反射機制生成一個實現代理介面的匿名類,在調用具體方法前調用InvokeHandler來處理。而cglib動態代理是利用asm開源包,對代理對象類的class文件載入進來,通過修改其位元組碼生成子類來處理。
1、如果目標對象實現了介面,默認情況下會採用JDK的動態代理實現AOP
2、如果目標對象實現了介面,可以強制使用CGLIB實現AOP
3、如果目標對象沒有實現了介面,必須採用CGLIB庫,spring會自動在JDK動態代理和CGLIB之間轉換

⑹ 動態代理jdk和cglib的區別

JDK和CGLIB生成動態代理類的區別
關於動態代理和靜態代理
當一個對象(客戶端)不能或者不想直接引用另一個對象(目標對象),這時可以應用代理模式在這兩者之間構建一個橋梁--代理對象。
按照代理對象的創建時期不同,可以分為兩種:
靜態代理:事先寫好代理對象類,在程序發布前就已經存在了;
動態代理:應用程序發布後,通過動態創建代理對象。
靜態代理其實就是一個典型的代理模式實現,在代理類中包裝一個被代理對象,然後影響被代理對象的行為,比較簡單,代碼就不放了。
其中動態代理又可分為:JDK動態代理和CGLIB代理。
1.JDK動態代理
此時代理對象和目標對象實現了相同的介面,目標對象作為代理對象的一個屬性,具體介面實現中,可以在調用目標對象相應方法前後加上其他業務處理邏輯。
代理模式在實際使用時需要指定具體的目標對象,如果為每個類都添加一個代理類的話,會導致類很多,同時如果不知道具體類的話,怎樣實現代理模式呢?這就引出動態代理。
JDK動態代理只能針對實現了介面的類生成代理。
2.CGLIB代理
CGLIB(CODE GENERLIZE LIBRARY)代理是針對類實現代理,
主要是對指定的類生成一個子類,覆蓋其中的所有方法,所以該類或方法不能聲明稱final的。

JDK動態代理和CGLIB代理生成的區別
JDK動態代理只能對實現了介面的類生成代理,而不能針對類 。
CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法 。
因為是繼承,所以該類或方法最好不要聲明成final ,final可以阻止繼承和多態。
PS:final 所修飾的數據具有「終態」的特徵,表示「最終的」意思:
final 修飾的類不能被繼承。
final 修飾的方法不能被子類重寫。
final 修飾的變數(成員變數或局部變數)即成為常量,只能賦值一次。
final 修飾的成員變數必須在聲明的同時賦值,如果在聲明的時候沒有賦值,那麼只有 一次賦值的機會,而且只能在構造方法中顯式賦值,然後才能使用。
final 修飾的局部變數可以只聲明不賦值,然後再進行一次性的賦值。
參考代碼
CGLIB:

1
2
3
4
5
6
7
8

public Object createProxyObject(Object obj) {
this.targetObject = obj;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());
enhancer.setCallback(this);
Object proxyObj = enhancer.create();
return proxyObj;// 返回代理對象,返回的對象其實就是一個封裝了「實現類」的代理類,是實現類的實例。
}

JDK:

1
2
3
4
5

public Object newProxy(Object targetObject) {// 將目標對象傳入進行代理
this.targetObject = targetObject; <br> //注意這個方法的參數,後面是類實現的介面
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);// 返回代理對象
}

在代碼中可以看到,在生成代理類時,傳遞的是實現類所實現的介面 targetObject.getClass().getInterfaces(),所以JDK只能對於介面進行做代理。如果換成類的話,則會拋java.lang.ClassCastException異常。
在Spring的源碼中,可以看到很多生成代理類的代碼。

動態代理的應用
AOP(Aspect-OrientedProgramming,面向切面編程),AOP包括切面(aspect)、通知(advice)、連接點(joinpoint),實現方式就是通過對目標對象的代理在連接點前後加入通知,完成統一的切面操作。
實現AOP的技術,主要分為兩大類:
一是採用動態代理技術,利用截取消息的方式,對該消息進行裝飾,以取代原有對象行為的執行;
二是採用靜態織入的方式,引入特定的語法創建「方面」,從而使得編譯器可以在編譯期間織入有關「方面」的代碼。
Spring提供了兩種方式來生成代理對象: JDKProxy和Cglib,具體使用哪種方式生成由AopProxyFactory根據AdvisedSupport對象的配置來決定。
默認的策略是如果目標類是介面,則使用JDK動態代理技術,如果目標對象沒有實現介面,則默認會採用CGLIB代理。
如果目標對象實現了介面,可以強制使用CGLIB實現代理(添加CGLIB庫,並在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)。

⑺ java動態代理和cglib動態代理的區別

1、Jdk動態代理實例:JDK動態代理只能代理實現了介面的類,其他普通類不能實現。代理類會在newProxyInstance方法中生成
2、cglib動態代理:cglib是針對類實現代理的,為代理的類生成一個子類,覆蓋方法實現增強,因為採用的是繼承所以不能代理final修飾的類。需要cglib和asm兩個jar包

⑻ 關於spring aop的cglib代理什麼時候才起作用

cglib(Code Generation Library)是一個強大的,高性能,高質量的Code生成類庫。它可以在運行期擴展Java類與實現Java介面。 cglib封裝了asm,可以在運行期動態生成新的class。 cglib用於AOP,jdk中的proxy必須基於介面,cglib卻沒有這個限制。 原理區別: java動態代理是利用反射機制生成一個實現代理介面的匿名類,在調用具體方法前調用InvokeHandler來處理。而cglib動態代理是利用asm開源包,對代理對象類的class文件載入進來,通過修改其位元組碼生成子類來處理。 1、如果目標對象實現了介面,默認情況下會採用JDK的動態代理實現AOP 2、如果目標對象實現了介面,可以強制使用CGLIB實現AOP 3、如果目標對象沒有實現了介面,必須採用CGLIB庫,spring會自動在JDK動態代理和CGLIB之間轉換 如何強制使用CGLIB實現AOP? * 添加CGLIB庫,SPRING_HOME/cglib/*.jar * 在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/> JDK動態代理和CGLIB位元組碼生成的區別? * JDK動態代理只能對實現了介面的類生成代理,而不能針對類 * CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法 因為是繼承,所以該類或方法最好不要聲明成final Java動態代理和CGLIB代理在其他方面沒什麼區別,只有 在Spring配置文件中配置的區別: <bean id="#" class="org.springframework.ProxyFactoryBean"> <property name="proxyTargetClass"> <value>true</value> </property> </bean> *************************************************** <bean id="#" class="org.springframework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>com.gc.impl.TimeBookInterface</value> </property> </bean>

閱讀全文

與java動態代理cglib相關的資料

熱點內容
編譯動態庫時會連接依賴庫嗎 瀏覽:706
淘寶手機加密是隨機的嗎 瀏覽:672
解壓包子怎麼裝飾 瀏覽:585
四個數湊24演算法 瀏覽:676
哪一種不是vi編譯器的模式 瀏覽:168
xp在此處打開命令窗口 瀏覽:128
代碼編譯運行用什麼軟體 瀏覽:997
動態庫在程序編譯時會被連接到 瀏覽:760
python超簡單編程 瀏覽:259
獲取命令方 瀏覽:976
怎樣製作文件夾和圖片 瀏覽:59
調研編譯寫信息 瀏覽:861
python馮諾依曼 瀏覽:419
同時安裝多個app有什麼影響 瀏覽:254
奧術殺戮命令宏 瀏覽:184
用sdes加密明文字母e 瀏覽:361
單片機原理及應用試題 瀏覽:425
易語言開啟指定文件夾 瀏覽:40
馬思純參加密室大逃脫 瀏覽:322
文件夾冬季澆築溫度 瀏覽:712