Java JDK與cglib動態(tài)代理有什么區(qū)別
一、說明
1.spring aop中的動態(tài)代理主要有兩種方式,jdk動態(tài)代理和cglib動態(tài)代理
2.從實現(xiàn)接口、繼承父類的角度討論區(qū)別
3.從限制角度討論區(qū)別
4.從性能上討論區(qū)別
二、區(qū)別
1.jdk動態(tài)代理只提供實現(xiàn)接口的目標類代理,不支持沒有實現(xiàn)接口的目標類的代理。如果目標類沒有實現(xiàn)接口,只能用cglib代理
2.jdk動態(tài)代理會在運行時為目標類生成一個動態(tài)代理類$proxy*.class。cglib的底層是通過ASM在運行時動態(tài)生成目標類的子類,還會有其它類
3. jdk動態(tài)代理的代理類實現(xiàn)了目標類實現(xiàn)的接口,并且會實現(xiàn)接口所有方法來代碼增強。cglib動態(tài)代理會重寫父類所有的方法來代碼增強
4.jdk動態(tài)代理調(diào)用時先去調(diào)用處理類進行增強,再通過反射的方式調(diào)用目標類的方法。cglib動態(tài)代理調(diào)用時先通過代理類進行增強,再直接調(diào)用父類對應(yīng)的方法進行調(diào)用目標方法
5.jdk動態(tài)代理如果目標類未實現(xiàn)接口則無法代理,cglib是通過繼承的方式來動態(tài)代理,若目標類被final關(guān)鍵字修飾,則無法使用cglib做動態(tài)代理
6.性能上:在老版的jdk,jdk代理生成的類速度快,通過反射調(diào)用慢,cglib是jdk代理速度的10倍左右,jdk在版本每次升級都會有很大的性能提升,cglib停滯不前,jdk7 8的動態(tài)代理性能在1萬次實驗中比cglib要快20%左右
三、代碼示例
3.1 靜態(tài)代理
package com.proxy.staticproxy;
public interface SellTicket {
void sell();
}
package com.proxy.staticproxy;
public class TrainStation implements SellTicket{
@Override
public void sell() {
System.out.println("火車站售票");
}
}
package com.proxy.staticproxy;
public class ProxyPoint implements SellTicket{
//聲明火車類對象
private TrainStation trainStation = new TrainStation();
@Override
public void sell() {
System.out.println("代售點收取服務(wù)費");
trainStation.sell();
}
public static void main(String[] args) {
ProxyPoint proxyPoint = new ProxyPoint();
proxyPoint.sell();
}
}
3.2 jdk動態(tài)代理
package com.proxy.jdkproxy;
import com.proxy.staticproxy.SellTicket;
import com.proxy.staticproxy.TrainStation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyFactory {
private TrainStation trainStation = new TrainStation();
public SellTicket getProxyPoint() {
/**
* ClassLoader loader: 類加載器,用于加載代理類??梢酝ㄟ^目標對象獲取類加載器
* Class<?>[] interfaces: 代理類實現(xiàn)的接口的字節(jié)碼對象
* InvocationHandler h: 代理對象的調(diào)用處理程序
*/
SellTicket sellTicket = (SellTicket)Proxy.newProxyInstance(trainStation.getClass().getClassLoader(), trainStation.getClass().getInterfaces(),
new InvocationHandler() {
/**
* @param proxy 代理對象 proxyObject是同一個對象,在invoke方法中基本不用
* @param method 對接口中的方法進行封裝的method對象
* @param args 調(diào)用方法的實際參數(shù)
* @return 方法返回值
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 代碼增強
System.out.println("代理點收取服務(wù)費");
Object object = method.invoke(trainStation, args);
return object;
}
});
return sellTicket;
}
public static void main(String[] args) {
ProxyFactory proxyPoint = new ProxyFactory();
SellTicket sellTicket = proxyPoint.getProxyPoint();
sellTicket.sell();
}
}
3.3 cglib動態(tài)代理
<!-- 引入cglib依賴包-->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
package com.cglib;
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 ProxyFactory implements MethodInterceptor {
private TrainStation trainStation = new TrainStation();
public TrainStation getTrainStation(){
//創(chuàng)建Enhancer對象,類似于JDK代理中的Proxy類
Enhancer enhancer = new Enhancer();
//設(shè)置父類的字節(jié)碼對象
enhancer.setSuperclass(TrainStation.class);
//設(shè)置回調(diào)函數(shù)
enhancer.setCallback(this);
//創(chuàng)建代理對象
TrainStation trainStation = (TrainStation)enhancer.create();
return trainStation;
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
// 代碼增強
System.out.println("代售點收取服務(wù)費用");
Object obj = method.invoke(trainStation, objects);
return obj;
}
public static void main(String[] args) throws Exception {
ProxyFactory proxyFactory = new ProxyFactory();
TrainStation trainStation = proxyFactory.getTrainStation();
trainStation.sell();
}
}
到此這篇關(guān)于Java JDK與cglib動態(tài)代理有什么區(qū)別的文章就介紹到這了,更多相關(guān)Java JDK動態(tài)代理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java8中用foreach循環(huán)獲取對象的index下標詳解
這篇文章主要給大家介紹了關(guān)于Java8中用foreach循環(huán)獲取對象的index下標的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
微服務(wù)之間如何通過feign調(diào)用接口上傳文件
這篇文章主要介紹了微服務(wù)之間如何通過feign調(diào)用接口上傳文件的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06
Scala數(shù)據(jù)庫連接池的簡單實現(xiàn)
本文主要介紹了Scala數(shù)據(jù)庫連接池的簡單實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02
Mybatis-Plus實現(xiàn)自動生成代碼的操作步驟
AutoGenerator 是 MyBatis-Plus 的代碼生成器,通過 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各個模塊的代碼,極大的提升了開發(fā)效率,本文將給大家介紹Mybatis-Plus實現(xiàn)自動生成代碼的操作步驟2023-10-10
解決springboot 2.x集成log4j2調(diào)試日志無法關(guān)閉的問題
這篇文章主要介紹了解決springboot 2.x集成log4j2調(diào)試日志無法關(guān)閉的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
JAVA使用POI獲取Excel的列數(shù)與行數(shù)
Apache POI 是用Java編寫的免費開源的跨平臺的 Java API,Apache POI提供API給Java程式對Microsoft Office格式檔案讀和寫的功能。 下面這篇文章給大家介紹了JAVA使用POI獲取Excel列數(shù)和行數(shù)的方法,有需要的朋友們可以參考借鑒,下面來一起看看吧。2016-12-12

