java做的k線圖網(wǎng)站源碼下載免費建自己的網(wǎng)址
面對新鮮事物,我們要先了解在去探索事物的本質(zhì)-默
目錄
一.介紹二者代理模式
1.1.Jdk代理模式
1.2cglib代理模式
1.3二者區(qū)別
1.3.1有無接口
1.3.2靈活性
1.4對于兩種代理模式的總結(jié)
1.4.1jdk代理模式
1.4.2cglib代理模式
二.兩種代理模式應(yīng)用場景
2.1jdk代理模式應(yīng)用場景
2.1.1基于接口的代理
2.1.2細粒度的方法攔截
2.2cglib代理模式應(yīng)用場景
2.2.1非基于接口的代理
2.2.2覆蓋父類中的方法?
2.2.3高性能的代理?
三.代碼演示?
3.1jdk代理模式
3.1.1源碼
?3.2思路解釋
3.2cglib代理模式
3.2.1源碼
?3.2.1思路解釋
一.介紹二者代理模式
1.1.Jdk代理模式
JDK代理是通過接口實現(xiàn)的動態(tài)代理方式。當目標類實現(xiàn)了至少一個接口時,Spring AOP會使用JDK代理。JDK代理通過在運行時創(chuàng)建一個實現(xiàn)了目標接口的代理類來實現(xiàn)代理功能。代理對象和目標對象實現(xiàn)了同一個接口,因此只能代理接口中定義的方法。
1.2cglib代理模式
CGLIB代理是通過繼承實現(xiàn)的動態(tài)代理方式。當目標類沒有實現(xiàn)任何接口時,Spring AOP會使用CGLIB代理。CGLIB代理通過在運行時創(chuàng)建目標類的子類來實現(xiàn)代理功能。代理對象繼承自目標對象,并覆蓋了目標對象的非final方法,因此可以代理目標對象的所有方法。
1.3二者區(qū)別
1.3.1有無接口
JDK代理要求目標類必須實現(xiàn)接口,而CGLIB代理不需要,可以代理普通的Java類。?
1.3.2靈活性
JDK代理基于接口,適用于對接口的代理,更加靈活,但無法代理沒有接口的類。
CGLIB代理是通過生成目標類的子類來實現(xiàn)代理,適用于對類的代理。CGLIB代理具有更高的性能,因為它不需要通過反射調(diào)用目標對象的方法。?
1.4對于兩種代理模式的總結(jié)
1.4.1jdk代理模式
JDK 動態(tài)代理是基于接口的代理方式。它通過創(chuàng)建一個實現(xiàn)了目標接口的代理類,并在代理類中實現(xiàn)代理邏輯。代理類在運行時動態(tài)生成,并在其中調(diào)用原始對象的方法
JDK 動態(tài)代理通過 java.lang.reflect.Proxy
類和 java.lang.reflect.InvocationHandler
接口來實現(xiàn)。代理對象是在運行時動態(tài)生成的。
無法代理非公有類:JDK 動態(tài)代理不能代理那些聲明為 final 的類,因為 final 類不能被繼承。另外,由于代理類是在運行時動態(tài)生成的,因此也無法代理那些沒有默認構(gòu)造函數(shù)的類。
方法攔截:代理對象在調(diào)用方法時,會將方法調(diào)用轉(zhuǎn)發(fā)給 InvocationHandler
的實現(xiàn)類,在這個實現(xiàn)類中可以添加自定義的邏輯,完成方法的攔截、增強等操作。
性能相對較低:相比于 CGLIB 動態(tài)代理,JDK 動態(tài)代理的性能較低。這主要是因為 JDK 動態(tài)代理需要通過反射來調(diào)用目標對象的方法。
總的來說,JDK 動態(tài)代理是一種比較常用的代理方式,適用于代理接口的場景,易于使用和理解。但它的局限性在于只能代理實現(xiàn)了接口的類,并且在性能方面稍遜于 CGLIB 動態(tài)代理。
1.4.2cglib代理模式
CGLIB 動態(tài)代理是一種基于繼承的代理方式。它通過創(chuàng)建目標類的子類來實現(xiàn)代理。代理類繼承自目標類,并重寫其中的方法,在重寫的方法中添加了增強邏輯。
類代理:CGLIB 動態(tài)代理可以代理類,無論是否實現(xiàn)了接口。這使得它可以代理那些沒有實現(xiàn)接口的類,不包括 final 類。
代理生成:CGLIB 動態(tài)代理使用字節(jié)碼生成庫來創(chuàng)建目標類的子類。代理類在運行時動態(tài)生成,并且不需要目標類實現(xiàn)任何接口。
方法攔截:被代理的方法在執(zhí)行時,會調(diào)用代理類中的方法。這樣,我們可以在代理類中添加攔截器(MethodInterceptor
),并在攔截器中實現(xiàn)自定義的邏輯。
性能相對較高:相比于 JDK 動態(tài)代理,CGLIB 動態(tài)代理的性能更高。這是因為 CGLIB 通過繼承來實現(xiàn)代理,避免了反射調(diào)用的開銷。
對于 final 方法和私有方法的限制:CGLIB 默認無法代理 final 方法,因為 final 方法無法被重寫。此外,CGLIB 也不能代理私有方法,因為代理類無法訪問目標類的私有方法。但是可以通過設(shè)置 CGLIB 的 Enhancer 對象的 setUseReflection(true)
方法來強制代理私有方法。這樣一來,CGLIB 將使用反射調(diào)用私有方法,但這可能會導(dǎo)致性能下降。
需要注意的是,CGLIB 代理依賴于字節(jié)碼生成,在代理類生成時會占用一定的時間和內(nèi)存。
總結(jié)來說,CGLIB 動態(tài)代理適用于代理類的場景,可以代理沒有實現(xiàn)接口的類,并且具有較高的性能。
二.兩種代理模式應(yīng)用場景
2.1jdk代理模式應(yīng)用場景
2.1.1基于接口的代理
如果目標對象實現(xiàn)了接口,可以使用JDK動態(tài)代理。它要求目標對象實現(xiàn)一個接口,并且生成的代理對象也會實現(xiàn)相同的接口。
2.1.2細粒度的方法攔截
JDK動態(tài)代理可以在目標對象的方法調(diào)用前后添加額外的邏輯。例如,在方法調(diào)用前打印日志、進行權(quán)限驗證或事務(wù)管理等
2.2cglib代理模式應(yīng)用場景
2.2.1非基于接口的代理
CGLIB動態(tài)代理可以代理沒有實現(xiàn)接口的類。因此,當目標對象沒有實現(xiàn)任何接口時,可以使用CGLIB動態(tài)代理。
2.2.2覆蓋父類中的方法?
CGLIB動態(tài)代理通過繼承目標類并覆蓋其中的方法來創(chuàng)建代理對象。這使得它可以代理目標類中的非公有方法。?
2.2.3高性能的代理?
相比JDK動態(tài)代理,CGLIB動態(tài)代理通常具有更高的性能,因為它直接操作字節(jié)碼而不需要通過反射調(diào)用方法。?
三.代碼演示?
3.1jdk代理模式
3.1.1源碼
package com.daili.jdk;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** @author lz* @create 2023-08-21 9:33*/
public interface UserService {void saveUser(String username);
}
class UserServiceImpl implements UserService {public void saveUser(String username) {System.out.println("Saving user: " + username);}
}class UserServiceProxy implements InvocationHandler {private Object target;public UserServiceProxy(Object target) {this.target = target;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Before method: " + method.getName());Object result = method.invoke(target, args);System.out.println("After method: " + method.getName());return result;}
}class Main {public static void main(String[] args) {UserService userService = new UserServiceImpl();UserService proxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),userService.getClass().getInterfaces(),new UserServiceProxy(userService));proxy.saveUser("劉兵");}
}
?3.2思路解釋
- 定義了一個接口?
UserService
,其中包含了一個抽象方法?saveUser(String username)
。 - 實現(xiàn)了接口?
UserService
?的具體類?UserServiceImpl
,該類實現(xiàn)了?saveUser
?方法,用于保存用戶信息。 - 創(chuàng)建了一個代理類?
UserServiceProxy
,實現(xiàn)了?InvocationHandler
?接口。在?invoke
?方法中,對目標方法進行前置和后置處理,即在目標方法執(zhí)行前輸出 "Before method: " + 方法名,在目標方法執(zhí)行后輸出 "After method: " + 方法名。 - 在?
Main
?類的?main
?方法中,創(chuàng)建了一個?UserServiceImpl
?的實例。 - 通過?
Proxy.newProxyInstance()
?方法創(chuàng)建代理對象,傳入目標對象的類加載器、接口數(shù)組和?UserServiceProxy
?的實例。返回的代理對象將會實現(xiàn)?UserService
?接口。 - 調(diào)用代理對象的?
saveUser("John")
?方法,實際上會觸發(fā)代理對象的?invoke
?方法,從而實現(xiàn)了動態(tài)代理。
在代碼執(zhí)行過程中,代理對象的 invoke
方法會先輸出 "Before method: saveUser",然后調(diào)用目標對象的 saveUser
方法,最后輸出 "After method: saveUser"。
通過 JDK 動態(tài)代理,可以在不修改目標對象代碼的情況下,對其方法進行增強、添加日志等操作。
3.2cglib代理模式
3.2.1源碼
package com.daili.cglib;import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** @author lz* @create 2023-08-21 9:49*/
public class UserService {public void saveUser(String username) {System.out.println("Saving user: " + username);}
}
class UserServiceInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("Before method: " + method.getName());Object result = proxy.invokeSuper(obj, args);System.out.println("After method: " + method.getName());return result;}static class Main {public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(UserService.class);enhancer.setCallback(new UserServiceInterceptor());UserService proxy = (UserService) enhancer.create();proxy.saveUser("劉兵");}
}
}
?3.2.1思路解釋
- 定義了一個類?
UserService
,其中包含了一個方法?saveUser(String username)
,用于保存用戶信息。 - 創(chuàng)建了一個代理類?
UserServiceInterceptor
,實現(xiàn)了?MethodInterceptor
?接口。在?intercept
?方法中,對目標方法進行前置和后置處理,即在目標方法執(zhí)行前輸出 "Before method: " + 方法名,在目標方法執(zhí)行后輸出 "After method: " + 方法名。使用?MethodProxy
?對象調(diào)用原始方法。 - 在?
Main
?類的?main
?方法中,創(chuàng)建了一個?Enhancer
?對象。 - 通過?
enhancer.setSuperclass(UserService.class)
?設(shè)置目標類為?UserService
。 - 通過?
enhancer.setCallback(new UserServiceInterceptor())
?設(shè)置回調(diào)處理器為?UserServiceInterceptor
?的實例。 - 調(diào)用?
enhancer.create()
?方法返回代理對象,將其轉(zhuǎn)換為?UserService
?類型。 - 調(diào)用代理對象的?
saveUser("John")
?方法,會觸發(fā)代理對象的?intercept
?方法,從而實現(xiàn)了動態(tài)代理。
在代碼執(zhí)行過程中,代理對象的 intercept
方法會先輸出 "Before method: saveUser",然后調(diào)用目標對象的 saveUser
方法,最后輸出 "After method: saveUser"。
通過 CGLIB 動態(tài)代理,可以在不修改目標對象代碼的情況下,對其方法進行增強、添加日志等操作。與 JDK 動態(tài)代理不同的是,CGLIB 動態(tài)代理可以代理類而不僅限于接口。