看故事学知识,这篇Java代理的文章妙啊!
這是我的第?208?期分享
作者 | java金融
來(lái)源 | java金融(ID:java4299)
分享 | Java中文社群(ID:javacn666)
什么是代理
代理模式是常用的java設(shè)計(jì)模式,他的特征是代理類(lèi)與委托類(lèi)有同樣的接口,代理類(lèi)主要負(fù)責(zé)為委托類(lèi)預(yù)處理消息、過(guò)濾消息、把消息轉(zhuǎn)發(fā)給委托類(lèi),以及事后處理消息等。代理類(lèi)與委托類(lèi)之間通常會(huì)存在關(guān)聯(lián)關(guān)系,一個(gè)代理類(lèi)的對(duì)象與一個(gè)委托類(lèi)的對(duì)象關(guān)聯(lián),代理類(lèi)的對(duì)象本身并不真正實(shí)現(xiàn)服務(wù),而是通過(guò)調(diào)用委托類(lèi)的對(duì)象的相關(guān)方法,來(lái)提供特定的服務(wù)。
代理其實(shí)不僅僅是在軟件開(kāi)發(fā)領(lǐng)域,在我們的日常生活中也是時(shí)常可見(jiàn)。比如某p2p老板突然攜款帶著小姨子跑路了,可憐了下面一堆的程序員背負(fù)一身房貸,上有老下有小,程序員只能被迫去申請(qǐng)勞動(dòng)仲裁,勞動(dòng)局就會(huì)為其指派一位代理律師全權(quán)負(fù)責(zé)程序員的仲裁事宜(PS:p2p跑路仲裁拿回工資的可能性非常低,沒(méi)讓你把工資退回就算好的了)。那這里面就是使用了代理模式,因?yàn)樵趧趧?dòng)仲裁這個(gè)活動(dòng)中,代理律師會(huì)全權(quán)代理程序員。比如:房東要將房子出售,于是到房地產(chǎn)中介公司找一個(gè)中介(代理),由他來(lái)幫房東完成銷(xiāo)售房屋,簽訂合同、網(wǎng)簽、貸款過(guò)戶(hù)等等事宜。
代理模式
這是常見(jiàn)代理模式常見(jiàn)的 UML 示意圖。 需要注意的有下面幾點(diǎn):
用戶(hù)只關(guān)心接口功能,而不在乎誰(shuí)提供了功能。上圖中接口是?Subject。
接口真正實(shí)現(xiàn)者是上圖的?RealSubject,但是它不與用戶(hù)直接接觸,而是通過(guò)代理。
代理就是上圖中的?Proxy,由于它實(shí)現(xiàn)了?Subject?接口,所以它能夠直接與用戶(hù)接觸。
用戶(hù)調(diào)用?Proxy?的時(shí)候,Proxy?內(nèi)部調(diào)用了?RealSubject。所以,Proxy?是中介者,它可以增強(qiáng)?RealSubject?操作。
代理又可以分為靜態(tài)代理和動(dòng)態(tài)代理兩種。我們先來(lái)看下靜態(tài)代理。
靜態(tài)代理
電影是電影公司委托給影院進(jìn)行播放的,但是影院可以在播放電影的時(shí)候,產(chǎn)生一些自己的經(jīng)濟(jì)收益,比如提供按摩椅,娃娃機(jī)(這個(gè)每次去電影院都會(huì)嘗試下,基本上是夾不起來(lái),有木有大神可以傳授下訣竅),賣(mài)爆米花、飲料(貴的要死,反正吃不起)等。我們平常去電影院看電影的時(shí)候,在電影開(kāi)始的階段是不是經(jīng)常會(huì)放廣告呢?然后在影片開(kāi)始結(jié)束時(shí)播放一些廣告。 下面我們通過(guò)代碼來(lái)模擬下電影院這一系列的賺錢(qián)操作。 首先得有一個(gè)接口,通用的接口是代理模式實(shí)現(xiàn)的基礎(chǔ)。這個(gè)接口我們命名為?Movie,代表電影播放的能力。
package?com.workit.demo.proxy;public?interface?Movie?{void?play(); }接下來(lái)我們要?jiǎng)?chuàng)建一個(gè)真正的實(shí)現(xiàn)這個(gè)?Movie?接口的類(lèi),和一個(gè)實(shí)現(xiàn)該接口的代理類(lèi)。 真正的類(lèi)《美國(guó)隊(duì)長(zhǎng)》電影:
代理類(lèi):
package?com.workit.demo.proxy;public?class?MovieStaticProxy?implements?Movie?{Movie?movie;public?MovieStaticProxy(Movie?movie)?{this.movie?=?movie;}@Overridepublic?void?play()?{playStart();movie.play();playEnd();}public?void?playStart()?{System.out.println("電影開(kāi)始前正在播放廣告");}public?void?playEnd()?{System.out.println("電影結(jié)束了,接續(xù)播放廣告");} }測(cè)試類(lèi):
package?com.workit.demo.proxy;package?com.workit.demo.proxy;public?class?StaticProxyTest?{public?static?void?main(String[]?args)?{Movie?captainAmericaMovie?=?new?CaptainAmericaMovie();Movie?movieStaticProxy?=?new?MovieStaticProxy(captainAmericaMovie);movieStaticProxy.play();} }運(yùn)行結(jié)果:
電影開(kāi)始前正在播放廣告 正在播放的電影是《美國(guó)隊(duì)長(zhǎng)》 電影結(jié)束了,接續(xù)播放廣告現(xiàn)在可以看到,代理模式可以在不修改被代理對(duì)象的基礎(chǔ)上,通過(guò)擴(kuò)展代理類(lèi),進(jìn)行一些功能的附加與增強(qiáng)。值得注意的是,代理類(lèi)和被代理類(lèi)應(yīng)該共同實(shí)現(xiàn)一個(gè)接口,或者是共同繼承某個(gè)類(lèi)。這個(gè)就是是靜態(tài)代理的內(nèi)容,為什么叫做靜態(tài)呢?因?yàn)樗念?lèi)型是事先預(yù)定好的,比如上面代碼中的?MovieStaticProxy?這個(gè)類(lèi)。
優(yōu)點(diǎn)
代理模式在客戶(hù)端與目標(biāo)對(duì)象之間起到一個(gè)中介作用和保護(hù)目標(biāo)對(duì)象的作用
代理對(duì)象可以擴(kuò)展目標(biāo)對(duì)象的功能
代理模式能將客戶(hù)端與目標(biāo)對(duì)象分離,在一定程度上降低了系統(tǒng)的耦合度。
缺點(diǎn)
代理對(duì)象需要與目標(biāo)對(duì)象實(shí)現(xiàn)一樣的接口,所以會(huì)有很多代理類(lèi),類(lèi)太多.同時(shí),一旦接口增加方法,目標(biāo)對(duì)象與代理對(duì)象都要維護(hù)。
jdk動(dòng)態(tài)代理
與靜態(tài)代理類(lèi)對(duì)照的是動(dòng)態(tài)代理類(lèi),動(dòng)態(tài)代理類(lèi)的字節(jié)碼在程序運(yùn)行時(shí)由Java反射機(jī)制動(dòng)態(tài)生成,無(wú)需程序員手工編寫(xiě)它的源代碼。動(dòng)態(tài)代理類(lèi)不僅簡(jiǎn)化了編程工作,而且提高了軟件系統(tǒng)的可擴(kuò)展性,因?yàn)镴ava 反射機(jī)制可以生成任意類(lèi)型的動(dòng)態(tài)代理類(lèi)。java.lang.reflect?包中的Proxy類(lèi)和InvocationHandler?接口提供了生成動(dòng)態(tài)代理類(lèi)的能力。
接著上面的例子,剛看完《美國(guó)隊(duì)長(zhǎng)》不過(guò)癮,還想繼續(xù)去看一場(chǎng)《鋼鐵俠》。一直在普通影廳看電影覺(jué)得沒(méi)啥意思,那就趕緊去VIP影廳(至今不知道長(zhǎng)啥樣子)體驗(yàn)一把。既然 實(shí)體店沒(méi)體驗(yàn)過(guò)那就用代碼來(lái)體驗(yàn)一次吧。創(chuàng)建一個(gè)VIPMovie電影接口
緊接著創(chuàng)建一個(gè)VIP影廳的播放實(shí)現(xiàn)類(lèi)
package?com.workit.demo.proxy;public?class?IronManVIPMovie?implements?VIPMovie?{@Overridepublic?void?vipPlay()?{System.out.println("VI影廳正在播放的電影是《鋼鐵俠》");} }如果按照靜態(tài)代理我們是不是又要?jiǎng)?chuàng)建一個(gè)VIP影廳播放的代理實(shí)現(xiàn)類(lèi),這種方式我們就不演示了。下面我們來(lái)看看通過(guò)動(dòng)態(tài)代理怎么來(lái)實(shí)現(xiàn)吧。
package?com.workit.demo.proxy;import?java.lang.reflect.InvocationHandler; import?java.lang.reflect.Method;public?class?MyInvocationHandler?implements?InvocationHandler?{private?Object?object;public?MyInvocationHandler(Object?object)?{this.object?=?object;}@Overridepublic?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?throws?Throwable?{playStart();Object?invoke?=?method.invoke(object,?args);playEnd();return?invoke;}public?void?playStart()?{System.out.println("電影開(kāi)始前正在播放廣告");}public?void?playEnd()?{System.out.println("電影結(jié)束了,接續(xù)播放廣告");} }MyInvocationHandler實(shí)現(xiàn)了?InvocationHandler?這個(gè)類(lèi),這個(gè)類(lèi)是什么意思呢?大家不要慌張,下面我會(huì)解釋。然后,我們就可以在VIP影廳看電影了。
package?com.workit.demo.proxy;import?java.lang.reflect.InvocationHandler; import?java.lang.reflect.Proxy;public?class?DynamicProxyTest?{public?static?void?main(String[]?args)?{IronManVIPMovie?ironManVIPMovie?=?new?IronManVIPMovie();InvocationHandler?invocationHandler?=?new?MyInvocationHandler(ironManVIPMovie);VIPMovie?dynamicProxy?=?(VIPMovie)?Proxy.newProxyInstance(IronManVIPMovie.class.getClassLoader(),IronManVIPMovie.class.getInterfaces(),?invocationHandler);dynamicProxy.vipPlay();} }輸出結(jié)果:
電影開(kāi)始前正在播放廣告 VI影廳正在播放的電影是《鋼鐵俠》 電影結(jié)束了,接續(xù)播放廣告看到?jīng)]有,我們并沒(méi)有像靜態(tài)代理那樣為?VIPMovie接口實(shí)現(xiàn)一個(gè)代理類(lèi),但最終它仍然實(shí)現(xiàn)了相同的功能,這其中的差別,就是之前討論的動(dòng)態(tài)代理所謂“動(dòng)態(tài)”的原因。 我們順帶把《美國(guó)隊(duì)長(zhǎng)》也用動(dòng)態(tài)代理實(shí)現(xiàn)下吧。
package?com.workit.demo.proxy;import?java.lang.reflect.InvocationHandler; import?java.lang.reflect.Proxy;public?class?DynamicProxyTest?{public?static?void?main(String[]?args)?{//?VIP?影廳《鋼鐵俠》IronManVIPMovie?ironManVIPMovie?=?new?IronManVIPMovie();InvocationHandler?invocationHandler?=?new?MyInvocationHandler(ironManVIPMovie);VIPMovie?dynamicProxy?=?(VIPMovie)?Proxy.newProxyInstance(IronManVIPMovie.class.getClassLoader(),IronManVIPMovie.class.getInterfaces(),?invocationHandler);dynamicProxy.vipPlay();//?普通影廳《美國(guó)隊(duì)長(zhǎng)》CaptainAmericaMovie?captainAmericaMovie?=?new?CaptainAmericaMovie();InvocationHandler?invocationHandler1?=?new?MyInvocationHandler(captainAmericaMovie);Movie?dynamicProxy1?=?(Movie)?Proxy.newProxyInstance(CaptainAmericaMovie.class.getClassLoader(),CaptainAmericaMovie.class.getInterfaces(),?invocationHandler1);dynamicProxy1.play();} }輸出結(jié)果:
電影開(kāi)始前正在播放廣告 VI影廳正在播放的電影是《鋼鐵俠》 電影結(jié)束了,接續(xù)播放廣告 電影開(kāi)始前正在播放廣告 正在播放的電影是《美國(guó)隊(duì)長(zhǎng)》 電影結(jié)束了,接續(xù)播放廣告我們通過(guò)?Proxy.newProxyInstance()?方法,卻產(chǎn)生了?Movie和?VIPMovie兩種接口的實(shí)現(xiàn)類(lèi)代理,這就是動(dòng)態(tài)代理的魔力。
JDK動(dòng)態(tài)代理到底是怎么實(shí)現(xiàn)的呢
動(dòng)態(tài)代碼涉及了一個(gè)非常重要的類(lèi)?Proxy。正是通過(guò)?Proxy?的靜態(tài)方法?newProxyInstance?才會(huì)動(dòng)態(tài)創(chuàng)建代理。具體怎么去創(chuàng)建代理類(lèi)就不分析了,感興趣的可以去看下源碼。我們直接看下生成的代理類(lèi)。 如何查看生成的代理類(lèi)? 在生成代理類(lèi)之前加上以下代碼(我用的jdk1.8):
?//新版本?jdk產(chǎn)生代理類(lèi)???System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles",?"true");如果上述代碼加上不生效可以考慮加下下面的代碼:
//?老版本jdk System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles",?"true"); //??該設(shè)置用于輸出cglib動(dòng)態(tài)代理產(chǎn)生的類(lèi) System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,?"C:\\class");??代碼如下:
??public?static?void?main(String[]?args)?{//新版本?jdk產(chǎn)生代理類(lèi)System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles",?"true");//?VIP?影廳《鋼鐵俠》IronManVIPMovie?ironManVIPMovie?=?new?IronManVIPMovie();InvocationHandler?invocationHandler?=?new?MyInvocationHandler(ironManVIPMovie);VIPMovie?dynamicProxy?=?(VIPMovie)?Proxy.newProxyInstance(IronManVIPMovie.class.getClassLoader(),IronManVIPMovie.class.getInterfaces(),?invocationHandler);dynamicProxy.vipPlay();//?普通影廳《美國(guó)隊(duì)長(zhǎng)》CaptainAmericaMovie?captainAmericaMovie?=?new?CaptainAmericaMovie();InvocationHandler?invocationHandler1?=?new?MyInvocationHandler(captainAmericaMovie);Movie?dynamicProxy1?=?(Movie)?Proxy.newProxyInstance(CaptainAmericaMovie.class.getClassLoader(),CaptainAmericaMovie.class.getInterfaces(),?invocationHandler1);dynamicProxy1.play();System.out.println("VIP?影廳《鋼鐵俠》代理類(lèi):"+dynamicProxy.getClass());System.out.println("普通影廳《美國(guó)隊(duì)長(zhǎng)》:"+dynamicProxy1.getClass());}我們可以看到結(jié)果
電影開(kāi)始前正在播放廣告 VI影廳正在播放的電影是《鋼鐵俠》 電影結(jié)束了,接續(xù)播放廣告 電影開(kāi)始前正在播放廣告 正在播放的電影是《美國(guó)隊(duì)長(zhǎng)》 電影結(jié)束了,接續(xù)播放廣告 VIP?影廳《鋼鐵俠》代理類(lèi):class?com.sun.proxy.$Proxy0 普通影廳《美國(guó)隊(duì)長(zhǎng)》:class?com.sun.proxy.$Proxy1產(chǎn)生了兩個(gè)代理類(lèi)分別是$Proxy0和$Proxy1。 下面?zhèn)儊?lái)看下"鋼鐵俠"的代理類(lèi)$Proxy0
// //?Source?code?recreated?from?a?.class?file?by?IntelliJ?IDEA //?(powered?by?Fernflower?decompiler) //package?com.sun.proxy;import?com.workit.demo.proxy.VIPMovie; import?java.lang.reflect.InvocationHandler; import?java.lang.reflect.Method; import?java.lang.reflect.Proxy; import?java.lang.reflect.UndeclaredThrowableException;public?final?class?$Proxy0?extends?Proxy?implements?VIPMovie?{private?static?Method?m1;private?static?Method?m3;private?static?Method?m2;private?static?Method?m0;public?$Proxy0(InvocationHandler?var1)?throws??{super(var1);}public?final?boolean?equals(Object?var1)?throws??{try?{return?(Boolean)super.h.invoke(this,?m1,?new?Object[]{var1});}?catch?(RuntimeException?|?Error?var3)?{throw?var3;}?catch?(Throwable?var4)?{throw?new?UndeclaredThrowableException(var4);}}public?final?void?vipPlay()?throws??{try?{super.h.invoke(this,?m3,?(Object[])null);}?catch?(RuntimeException?|?Error?var2)?{throw?var2;}?catch?(Throwable?var3)?{throw?new?UndeclaredThrowableException(var3);}}public?final?String?toString()?throws??{try?{return?(String)super.h.invoke(this,?m2,?(Object[])null);}?catch?(RuntimeException?|?Error?var2)?{throw?var2;}?catch?(Throwable?var3)?{throw?new?UndeclaredThrowableException(var3);}}public?final?int?hashCode()?throws??{try?{return?(Integer)super.h.invoke(this,?m0,?(Object[])null);}?catch?(RuntimeException?|?Error?var2)?{throw?var2;}?catch?(Throwable?var3)?{throw?new?UndeclaredThrowableException(var3);}}static?{try?{m1?=?Class.forName("java.lang.Object").getMethod("equals",?Class.forName("java.lang.Object"));m3?=?Class.forName("com.workit.demo.proxy.VIPMovie").getMethod("vipPlay");m2?=?Class.forName("java.lang.Object").getMethod("toString");m0?=?Class.forName("java.lang.Object").getMethod("hashCode");}?catch?(NoSuchMethodException?var2)?{throw?new?NoSuchMethodError(var2.getMessage());}?catch?(ClassNotFoundException?var3)?{throw?new?NoClassDefFoundError(var3.getMessage());}} },通過(guò)上述代碼我們可以看到?$Proxy0 extends Proxy implements VIPMovie繼承了Proxy?且實(shí)現(xiàn)了VIPMovie接口,這也就是為什么jdk動(dòng)態(tài)代理必須基于接口,java 是單繼承的。 然后再看下代理類(lèi)實(shí)現(xiàn)的方法:
?public?final?void?vipPlay()?throws??{try?{super.h.invoke(this,?m3,?(Object[])null);}?catch?(RuntimeException?|?Error?var2)?{throw?var2;}?catch?(Throwable?var3)?{throw?new?UndeclaredThrowableException(var3);}}這個(gè)supper.h.invoke Proxy中的h的invoke方法,即InvocationHandler.invoke也就是上面?MyInvocationHandler.invoke方法,至此整個(gè)流程就清晰了。這就是jdk的動(dòng)態(tài)代理。
cglib動(dòng)態(tài)代理
上面說(shuō)jdk動(dòng)態(tài)代理只能基于接口,那么如果是類(lèi)要?jiǎng)討B(tài)代理怎么辦呢?cglib動(dòng)態(tài)代理就可解決關(guān)于類(lèi)的動(dòng)態(tài)代理。 下面我們來(lái)創(chuàng)建一個(gè)“《美國(guó)隊(duì)長(zhǎng)2》”
package?com.workit.demo.proxy;public?class?CaptainAmerica2MovieImpl?{public?void?play(){System.out.println("正在播放的電影是《美國(guó)隊(duì)長(zhǎng)2》");} }引入cglib pom依賴(lài)
<!--?https://mvnrepository.com/artifact/cglib/cglib?--> <dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version> </dependency>創(chuàng)建一個(gè)自定義MethodInterceptor。
package?com.workit.demo.proxy;import?net.sf.cglib.proxy.MethodInterceptor; import?net.sf.cglib.proxy.MethodProxy;import?java.lang.reflect.Method;public?class?CglibProxyInterceptor?implements?MethodInterceptor?{@Overridepublic?Object?intercept(Object?o,?Method?method,?Object[]?objects,?MethodProxy?methodProxy)?throws?Throwable?{playStart();Object?object?=?methodProxy.invokeSuper(o,?objects);playEnd();return?object;}public?void?playStart()?{System.out.println("電影開(kāi)始前正在播放廣告");}public?void?playEnd()?{System.out.println("電影結(jié)束了,接續(xù)播放廣告");} }測(cè)試類(lèi)
package?com.workit.demo.proxy;import?net.sf.cglib.core.DebuggingClassWriter; import?net.sf.cglib.proxy.Enhancer;public?class?CglibProxyTest?{public?static?void?main(String[]?args)?{//?//在指定目錄下生成動(dòng)態(tài)代理類(lèi)System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,?"C:\\class");//創(chuàng)建Enhancer對(duì)象,類(lèi)似于JDK動(dòng)態(tài)代理的Proxy類(lèi),下一步就是設(shè)置幾個(gè)參數(shù)Enhancer?enhancer?=?new?Enhancer();//設(shè)置目標(biāo)類(lèi)的字節(jié)碼文件enhancer.setSuperclass(CaptainAmerica2MovieImpl.class);//設(shè)置回調(diào)函數(shù)enhancer.setCallback(new?CglibProxyInterceptor());//這里的creat方法就是正式創(chuàng)建代理類(lèi)CaptainAmerica2MovieImpl?captainAmerica2Movie?=?(CaptainAmerica2MovieImpl)enhancer.create();//調(diào)用代理類(lèi)的play方法captainAmerica2Movie.play();System.out.println("cglib動(dòng)態(tài)代理《美國(guó)隊(duì)長(zhǎng)2》:"+captainAmerica2Movie.getClass());} }輸出結(jié)果:
電影開(kāi)始前正在播放廣告 正在播放的電影是《美國(guó)隊(duì)長(zhǎng)2》 電影結(jié)束了,接續(xù)播放廣告 cglib動(dòng)態(tài)代理《美國(guó)隊(duì)長(zhǎng)2》:class?com.workit.demo.proxy.CaptainAmerica2MovieImpl$$EnhancerByCGLIB$$5c3ddcfe我們看下最終創(chuàng)建的代理類(lèi)生成的play方法
public?class?CaptainAmerica2MovieImpl$$EnhancerByCGLIB$$5c3ddcfe?extends?CaptainAmerica2MovieImpl?implements?Factory?{public?final?void?play()?{MethodInterceptor?var10000?=?this.CGLIB$CALLBACK_0;if?(var10000?==?null)?{CGLIB$BIND_CALLBACKS(this);var10000?=?this.CGLIB$CALLBACK_0;}if?(var10000?!=?null)?{var10000.intercept(this,?CGLIB$play$0$Method,?CGLIB$emptyArgs,?CGLIB$play$0$Proxy);}?else?{super.play();}}從代理對(duì)象反編譯源碼可以知道,代理對(duì)象繼承于CaptainAmerica2MovieImpl?,攔截器調(diào)用intercept()方法,?intercept()方法由自定義CglibProxyInterceptor實(shí)現(xiàn),所以,最后調(diào)用CglibProxyInterceptor中的intercept()方法,從而完成了由代理對(duì)象訪問(wèn)到目標(biāo)對(duì)象的動(dòng)態(tài)代理實(shí)現(xiàn)。
CGlib是一個(gè)強(qiáng)大的,高性能,高質(zhì)量的Code生成類(lèi)庫(kù)。它可以在運(yùn)行期擴(kuò)展Java類(lèi)與實(shí)現(xiàn)Java接口。
用CGlib生成代理類(lèi)是目標(biāo)類(lèi)的子類(lèi)。
用CGlib生成 代理類(lèi)不需要接口。
用CGLib生成的代理類(lèi)重寫(xiě)了父類(lèi)的各個(gè)方法。
攔截器中的intercept方法內(nèi)容正好就是代理類(lèi)中的方法體。
總結(jié)
代理分為靜態(tài)代理和動(dòng)態(tài)代理兩種。
靜態(tài)代理,代理類(lèi)需要自己編寫(xiě)代碼寫(xiě)成。
動(dòng)態(tài)代理有jdk和cglib,代理類(lèi)通過(guò)?Proxy.newInstance()或者ASM?生成。
靜態(tài)代理和動(dòng)態(tài)代理的區(qū)別是在于要不要開(kāi)發(fā)者自己定義 Proxy 類(lèi)。 動(dòng)態(tài)代理通過(guò)?Proxy?動(dòng)態(tài)生成?proxy class,但是它也指定了一個(gè)?InvocationHandler?或者?MethodInterceptor的實(shí)現(xiàn)類(lèi)。
代理模式本質(zhì)上的目的是為了增強(qiáng)現(xiàn)有代碼的功能。
結(jié)束
由于自己才疏學(xué)淺,難免會(huì)有紕漏,假如你發(fā)現(xiàn)了錯(cuò)誤的地方,還望留言給我指出來(lái),我會(huì)對(duì)其加以修正。
如果你覺(jué)得文章還不錯(cuò),你的轉(zhuǎn)發(fā)、分享、贊賞、點(diǎn)贊、留言就是對(duì)我最大的鼓勵(lì)。
感謝您的閱讀,十分歡迎并感謝您的關(guān)注。
參考
https://blog.csdn.net/m0_37314675/article/details/77850967 https://www.cnblogs.com/cC-Zhou/p/9525638.html https://www.jianshu.com/p/4539e6d9f337
往期推薦啪啪打臉!領(lǐng)導(dǎo)說(shuō):try-catch要放在循環(huán)體外!
阿里巴巴為什么讓初始化集合時(shí)必須指定大小?
關(guān)注公眾號(hào)發(fā)送”進(jìn)群“,磊哥拉你進(jìn)讀者群。
總結(jié)
以上是生活随笔為你收集整理的看故事学知识,这篇Java代理的文章妙啊!的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 2017年AR大会上海站干货分享
- 下一篇: 漫画:Java如何实现热更新?