2023-07-05 10:30:54來源:Java技術(shù)指北
哈嘍,大家好,我是了不起。如題,這個(gè)問題應(yīng)該面試??碱},當(dāng)你遇到這個(gè)問題時(shí),如果你能回答出來JDK動(dòng)態(tài)代理的原理,然后引申Cglib 動(dòng)態(tài)代理,那么這個(gè)面試官一定會(huì)對(duì)你刮目相看。
(相關(guān)資料圖)
在Java中,動(dòng)態(tài)代理是一種機(jī)制,允許在運(yùn)行時(shí)動(dòng)態(tài)地創(chuàng)建代理對(duì)象來代替某個(gè)實(shí)際對(duì)象,從而在其前后執(zhí)行額外的邏輯。
為什么JDK動(dòng)態(tài)代理只能代理接口實(shí)現(xiàn)類,原因是JDK動(dòng)態(tài)代理是基于接口實(shí)現(xiàn)的。
當(dāng)你使用Proxy類創(chuàng)建代理對(duì)象時(shí),你需要指定一個(gè)接口列表來表示代理對(duì)象所應(yīng)該實(shí)現(xiàn)的接口,這些接口就成為代理對(duì)象的類型。
具體來說,代理對(duì)象的方法調(diào)用會(huì)被轉(zhuǎn)發(fā)到實(shí)現(xiàn)InvocationHandler接口的類中的invoke()方法。這個(gè)invoke()方法接受三個(gè)參數(shù):代理對(duì)象本身、被調(diào)用的方法對(duì)象和方法的參數(shù)數(shù)組。invoke()方法需要返回被代理方法調(diào)用的結(jié)果。
由于代理對(duì)象的類型是由接口列表決定的,因此只有實(shí)現(xiàn)了接口的類才能被代理。如果你想代理一個(gè)類而不是一個(gè)接口,你需要使用其他的代理技術(shù),比如CGLIB。
1、JDK動(dòng)態(tài)代理代碼實(shí)例下面是一個(gè)簡(jiǎn)單的示例代碼,展示了如何使用JDK動(dòng)態(tài)代理來創(chuàng)建代理對(duì)象。
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class ProxyDemo { public static void main(String[] args) { RealObject real = new RealObject(); InvocationHandler handler = new DynamicProxy(real); // 創(chuàng)建代理對(duì)象 MyInterface proxy = (MyInterface) Proxy.newProxyInstance( MyInterface.class.getClassLoader(), new Class>[] { MyInterface.class }, handler); // 調(diào)用代理對(duì)象的方法 proxy.doSomething(); }}interface MyInterface { void doSomething();}class RealObject implements MyInterface { public void doSomething() { System.out.println("RealObject doSomething"); }}class DynamicProxy implements InvocationHandler { private Object target; public DynamicProxy(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before method invocation"); Object result = method.invoke(target, args); System.out.println("After method invocation"); return result; }}
在上面的代碼中,RealObject實(shí)現(xiàn)了MyInterface接口,它是我們要代理的實(shí)際對(duì)象。DynamicProxy類實(shí)現(xiàn)了InvocationHandler接口,并在invoke()方法中添加了額外的邏輯,用于在代理對(duì)象方法調(diào)用前后執(zhí)行。
在main()方法中,我們使用Proxy.newProxyInstance()方法創(chuàng)建代理對(duì)象。我們指定了MyInterface接口作為代理對(duì)象類型,并將DynamicProxy對(duì)象作為代理對(duì)象的InvocationHandler。
最后,我們調(diào)用代理對(duì)象的doSomething()方法,并觀察控制臺(tái)輸出的結(jié)果。
需要注意的是,代理對(duì)象的方法調(diào)用都會(huì)被轉(zhuǎn)發(fā)到DynamicProxy類的invoke()方法中進(jìn)行處理,因此在這個(gè)示例中,實(shí)際的RealObject對(duì)象的doSomething()方法的執(zhí)行是在invoke()方法中通過反射進(jìn)行的。
總結(jié)一下,JDK動(dòng)態(tài)代理只能代理接口實(shí)現(xiàn)類,原因是JDK動(dòng)態(tài)代理是基于接口實(shí)現(xiàn)的,代理對(duì)象的類型由接口列表決定。如果你想代理一個(gè)類而不是一個(gè)接口,你需要使用其他的代理技術(shù),比如CGLIB。
2、Cglib 代碼演示以下是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 CGLIBProxyDemo { public static void main(String[] args) { RealObject real = new RealObject(); MethodInterceptor handler = new CGLIBProxy(real); // 創(chuàng)建代理對(duì)象 RealObject proxy = (RealObject) Enhancer.create( RealObject.class, handler); // 調(diào)用代理對(duì)象的方法 proxy.doSomething(); }}class CGLIBProxy implements MethodInterceptor { private Object target; public CGLIBProxy(Object target) { this.target = target; } public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Before method invocation"); Object result = proxy.invoke(target, args); System.out.println("After method invocation"); return result; }}
在上面的示例中,我們使用CGLIB的Enhancer類和MethodInterceptor接口來創(chuàng)建代理對(duì)象。RealObject類不再需要實(shí)現(xiàn)接口,而是直接作為代理對(duì)象的類型。在CGLIBProxy類中,我們實(shí)現(xiàn)了MethodInterceptor接口,并在intercept()方法中添加了額外的邏輯。
在main()方法中,我們使用Enhancer.create()方法創(chuàng)建代理對(duì)象。我們指定了RealObject類作為代理對(duì)象類型,并將CGLIBProxy對(duì)象作為代理對(duì)象的MethodInterceptor。最后,我們調(diào)用代理對(duì)象的doSomething()方法,并觀察控制臺(tái)輸出的結(jié)果。
需要注意的是,CGLIB代理使用字節(jié)碼技術(shù)來生成代理對(duì)象,因此它的效率比JDK動(dòng)態(tài)代理要高,但是它也需要額外的庫(kù)依賴。
3、兩者優(yōu)缺點(diǎn)JDK動(dòng)態(tài)代理和CGLIB代理都有它們自己的優(yōu)缺點(diǎn)。
JDK動(dòng)態(tài)代理的優(yōu)點(diǎn):
JDK動(dòng)態(tài)代理是Java標(biāo)準(zhǔn)庫(kù)的一部分,因此它不需要引入任何外部依賴。JDK動(dòng)態(tài)代理只需要實(shí)現(xiàn)接口即可生成代理對(duì)象,不需要改變?cè)蓄惖慕Y(jié)構(gòu)。由于JDK動(dòng)態(tài)代理是基于接口實(shí)現(xiàn)的,因此它更適合用于代理接口實(shí)現(xiàn)類的場(chǎng)景。JDK動(dòng)態(tài)代理的缺點(diǎn):
JDK動(dòng)態(tài)代理只能代理實(shí)現(xiàn)了接口的類,無法代理沒有實(shí)現(xiàn)接口的類。JDK動(dòng)態(tài)代理在生成代理對(duì)象時(shí),需要使用反射機(jī)制,因此它的效率相對(duì)較低。CGLIB代理的優(yōu)點(diǎn):
CGLIB代理是基于字節(jié)碼技術(shù)實(shí)現(xiàn)的,因此它的效率比JDK動(dòng)態(tài)代理更高。CGLIB代理可以代理沒有實(shí)現(xiàn)接口的類。CGLIB代理的缺點(diǎn):
CGLIB代理需要引入外部依賴。CGLIB代理在生成代理對(duì)象時(shí),需要改變?cè)蓄惖慕Y(jié)構(gòu),因此它可能會(huì)引起一些問題,例如無法代理final類或final方法等問題。綜上所述,JDK動(dòng)態(tài)代理適用于代理接口實(shí)現(xiàn)類的場(chǎng)景,而CGLIB代理適用于代理沒有實(shí)現(xiàn)接口的類的場(chǎng)景。如果你需要代理接口實(shí)現(xiàn)類,而且不想引入額外的依賴,那么JDK動(dòng)態(tài)代理是一個(gè)不錯(cuò)的選擇;如果你需要代理沒有實(shí)現(xiàn)接口的類,那么CGLIB代理可能更適合你的需求。
關(guān)鍵詞:
哈嘍,大家好,我是了不起。如題,這個(gè)問題應(yīng)該面試常考題,當(dāng)你遇到這
flag包作用Golang中的flag包用于解析命令行參數(shù),提供了一個(gè)方便的接口
一、背景1 1什么是精細(xì)化運(yùn)營(yíng)?用戶畫像:注重用戶細(xì)分,深入分析用戶
隨著大模型的發(fā)展,尤其是近來各種開源大模型的發(fā)布,如何對(duì)各種模型進(jìn)
博德之門3怎么增加暴擊率的問題原因是什么?博德之門3是一款非常熱門的
綾致時(shí)裝Bestseller1975年始建于丹麥,創(chuàng)始人為TroelsHolchPovlsen。Bestseller
江粉兒從內(nèi)江華潤(rùn)燃?xì)夥?wù)號(hào)獲悉,內(nèi)江城區(qū)這些區(qū)域?qū)⑼?,詳情如下?/p>
中新網(wǎng)7月5日電 據(jù)北京市氣象局官方微博消息,北京市應(yīng)急管理局提
為切實(shí)做好控?zé)煿ぷ鳎M(jìn)一步提高全社會(huì)控?zé)熞庾R(shí),努力營(yíng)造一個(gè)清潔無煙
大家好,最近小紅發(fā)現(xiàn)有諸多的小伙伴們對(duì)于dnf進(jìn)游戲很慢什么原因,dnf
記者從第十四屆全國(guó)冬季運(yùn)動(dòng)會(huì)組委會(huì)了解到,為進(jìn)一步鞏固和擴(kuò)大“帶動(dòng)
英國(guó)倫敦股市《金融時(shí)報(bào)》100種股票平均價(jià)格指數(shù)4日下跌---新華社快訊
共享滑板單車投放至位于江蘇省淮安市的江蘇食品藥品職業(yè)技術(shù)學(xué)院校園,
據(jù)TA凱爾特人記者JaredWeiss報(bào)道,消息人士透露,凱爾特人會(huì)在處理完格
1、專升本的確是??粕@得本科學(xué)歷的最好、含金量最高的途徑。2、但需