日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

设计模式:代理模式是什么,Spring AOP还和它有关系?

發(fā)布時(shí)間:2025/3/14 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 设计模式:代理模式是什么,Spring AOP还和它有关系? 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

接著學(xué)習(xí)設(shè)計(jì)模式系列,今天講解的是代理模式。

定義

什么是代理模式?

代理模式,也叫委托模式,其定義是給某一個(gè)對(duì)象提供一個(gè)代理對(duì)象,并由代理對(duì)象控制對(duì)原對(duì)象的引用。它包含了三個(gè)角色:

Subject:抽象主題角色。可以是抽象類也可以是接口,是一個(gè)最普通的業(yè)務(wù)類型定義。

RealSubject:具體主題角色,也就是被代理的對(duì)象,是業(yè)務(wù)邏輯的具體執(zhí)行者。

Proxy:代理主題角色。負(fù)責(zé)讀具體主題角色的引用,通過(guò)真實(shí)角色的業(yè)務(wù)邏輯方法來(lái)實(shí)現(xiàn)抽象方法,并在前后可以附加自己的操作。

用類圖來(lái)表示的話大概如下:

我們可以用舉一個(gè)電影演員拍戲的例子,一般來(lái)說(shuō),演員最主要的工作就是演戲,其他的事可以交給他的經(jīng)紀(jì)人去做,例如談合同,安排檔期等等,而負(fù)責(zé)這些場(chǎng)外工作的經(jīng)紀(jì)人就相當(dāng)于Proxy,而負(fù)責(zé)核心業(yè)務(wù)的演員就是 RealSubject 。

這就是代理模式的設(shè)計(jì)思路,除此之外,代理模式分為靜態(tài)代理和動(dòng)態(tài)代理,靜態(tài)代理是我們自己創(chuàng)建一個(gè)代理類,而動(dòng)態(tài)代理是程序自動(dòng)幫我們生成一個(gè)代理類,可以在程序運(yùn)行時(shí)再生成對(duì)象,下面分別對(duì)它們做介紹。

靜態(tài)代理

靜態(tài)代理在程序運(yùn)行之前,代理類.class文件就已經(jīng)被創(chuàng)建了。還是用上面演員演戲的例子,在靜態(tài)代理模式中,我們要先創(chuàng)建一個(gè)抽象主題角色 Star

public interface Star {// 演戲void act(); }

接下來(lái)就是創(chuàng)建具體的主題角色和代理主題角色,分別實(shí)現(xiàn)這個(gè)接口,先創(chuàng)建一個(gè)具體的主題角色 Actor

/*** 演員,也就是具體的主題角色** @author Tao* @since 2019/7/9 18:34*/ public class Actor implements Star {public void act() {System.out.println("演員演戲~~~");} }

然后就是創(chuàng)建代理主題角色,也就是代理類,代理類本身并不負(fù)責(zé)核心業(yè)務(wù)的執(zhí)行流程,演戲這事還得明星自己來(lái)。所以在代理類中需要將真實(shí)對(duì)象引入,下面是具體的代碼實(shí)現(xiàn):

/*** 代理對(duì)象* @author Tao* @since 2019/7/9 18:43*/ public class Agent implements Star {/*** 接收真實(shí)的明星對(duì)象*/private Star star;/*** 通過(guò)構(gòu)造方法傳進(jìn)來(lái)真實(shí)的明星對(duì)象** @param star star*/public Agent(Star star) {this.star = star;}public void act() {System.out.println("簽合同");star.act();System.out.println("演完戲就收錢(qián)了");} }

代碼的邏輯還是比較清晰的,通過(guò)維護(hù)一個(gè)Star對(duì)象,可以在act里調(diào)用具體主題角色的業(yè)務(wù)邏輯,并且在核心邏輯前后可以做一些輔助操作,比如簽合同,收錢(qián)等,這樣代理模式的角色就都分工完成了,最后用一個(gè)場(chǎng)景類來(lái)驗(yàn)證下:

public class Client {public static void main(String[] args) {Star actor = new Actor();Agent agent = new Agent(actor);agent.act();} }

運(yùn)行的結(jié)果如下:

簽合同
演員演戲~~~
演完戲就收錢(qián)了

動(dòng)態(tài)代理

動(dòng)態(tài)代理分為兩種,分別是JDK動(dòng)態(tài)代理和 CGLIB 動(dòng)態(tài)代理,怎么又分了,代理模式分類真多,不過(guò)來(lái)都來(lái)了,就都學(xué)習(xí)一下吧。

JDK動(dòng)態(tài)代理

前面說(shuō)了,在動(dòng)態(tài)代理中我們不再需要再手動(dòng)的創(chuàng)建代理類,我們只需要編寫(xiě)一個(gè)動(dòng)態(tài)處理器就可以了。真正的代理對(duì)象由JDK再運(yùn)行時(shí)幫我們動(dòng)態(tài)的來(lái)創(chuàng)建。

/*** 動(dòng)態(tài)代理處理類** @author Tao* @since 2019/7/9 19:04*/ public class JdkProxyHandler {/*** 用來(lái)接收真實(shí)明星對(duì)象*/private Object star;/*** 通過(guò)構(gòu)造方法傳進(jìn)來(lái)真實(shí)的明星對(duì)象** @param star star*/public JdkProxyHandler(Star star) {super();this.star = star;}/*** 給真實(shí)對(duì)象生成一個(gè)代理對(duì)象實(shí)例** @return Object*/public Object getProxyInstance() {return Proxy.newProxyInstance(star.getClass().getClassLoader(),star.getClass().getInterfaces(), (proxy, method, args) -> {System.out.println("簽合同");// 執(zhí)行具體的業(yè)務(wù)邏輯Object object = method.invoke(star, args);System.out.println("演出完經(jīng)紀(jì)人去收錢(qián)……");return object;});} }

這里說(shuō)一下Proxy.newProxyInstance 這個(gè)方法,該方法包含了三個(gè)參數(shù),

  • ClassLoader loader:指定當(dāng)前目標(biāo)對(duì)象使用的類加載器,獲取加載器的方法是固定的;
  • Class<?>[] interfaces:指定目標(biāo)對(duì)象實(shí)現(xiàn)的接口的類型,使用泛型方式確認(rèn)類型;
  • InvocationHandler:指定動(dòng)態(tài)處理器,執(zhí)行目標(biāo)對(duì)象的方法時(shí)會(huì)觸發(fā)事件處理器的方法。

寫(xiě)完了動(dòng)態(tài)代理實(shí)現(xiàn)類,我們寫(xiě)個(gè)場(chǎng)景類測(cè)試下,

public class Client {public static void main(String[] args) {Star actor = new Actor();// 創(chuàng)建動(dòng)態(tài)代理對(duì)象實(shí)例Star jdkProxy = (Star) new JdkProxyHandler(actor).getProxyInstance();jdkProxy.act();} }

執(zhí)行結(jié)果正常輸出:

簽合同
演員演戲~~~
演出完代理去收錢(qián)……

由此可見(jiàn),JDK 動(dòng)態(tài)代理確實(shí)發(fā)揮了代理的功能,相對(duì)于靜態(tài)代理,JDK 動(dòng)態(tài)代理大大減少了我們的開(kāi)發(fā)任務(wù),同時(shí)減少了對(duì)業(yè)務(wù)接口的依賴,降低了耦合度。但它同樣有缺陷,就是動(dòng)態(tài)代理的實(shí)現(xiàn)類需要類實(shí)現(xiàn)接口來(lái)完成代理的業(yè)務(wù),也就是說(shuō)它始終無(wú)法擺脫僅支持interface代理的桎梏,這是設(shè)計(jì)上的缺陷。而這時(shí)CGLIB 動(dòng)態(tài)代理就派上用場(chǎng)了。

CGLIB 動(dòng)態(tài)代理

CGLib采用了非常底層的字節(jié)碼技術(shù),其原理是通過(guò)字節(jié)碼技術(shù)為一個(gè)類創(chuàng)建子類,并在子類中采用方法攔截的技術(shù)攔截所有父類方法的調(diào)用,順勢(shì)織入橫切邏輯。但因?yàn)椴捎玫氖抢^承,所以不能對(duì)final修飾的類進(jìn)行代理。下面我們寫(xiě)一個(gè)關(guān)于CGLib的動(dòng)態(tài)代理類,值得說(shuō)下的是,CGLib所在的依賴包不是JDK本身就有的,所以我們需要額外引入,如果是用maven來(lái)管理的話,就可以直接引入如下的依賴:

<dependencies><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.2.3</version></dependency> </dependencies>

使用 CGLIB 需要實(shí)現(xiàn) MethodInterceptor 接口,并重寫(xiě)intercept 方法,在該方法中對(duì)原始要執(zhí)行的方法前后做增強(qiáng)處理。該類的代理對(duì)象可以使用代碼中的字節(jié)碼增強(qiáng)器來(lái)獲取。具體的代碼如下:

public class CglibProxy implements MethodInterceptor {/*** 維護(hù)目標(biāo)對(duì)象*/private Object target;public Object getProxyInstance(final Object target) {this.target = target;// Enhancer類是CGLIB中的一個(gè)字節(jié)碼增強(qiáng)器,它可以方便的對(duì)你想要處理的類進(jìn)行擴(kuò)展Enhancer enhancer = new Enhancer();// 將被代理的對(duì)象設(shè)置成父類enhancer.setSuperclass(this.target.getClass());// 回調(diào)方法,設(shè)置攔截器enhancer.setCallback(this);// 動(dòng)態(tài)創(chuàng)建一個(gè)代理類return enhancer.create();}public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("簽合同");// 執(zhí)行具體的業(yè)務(wù)邏輯Object result = methodProxy.invoke(o, objects);System.out.println("演出完經(jīng)紀(jì)人去收錢(qián)……");return result;} }場(chǎng)景測(cè)試類: public class Client {public static void main(String[] args) {Star actor = new Actor();// 創(chuàng)建動(dòng)態(tài)代理對(duì)象實(shí)例Star proxy = (Star) new CglibProxy().getProxyInstance(actor);proxy.act();} }

可以看出,測(cè)試類的邏輯和JDK動(dòng)態(tài)代理差不多,其實(shí)套路都是一樣的,其實(shí)技術(shù)實(shí)現(xiàn)不同。

總結(jié)一下CGLIB代理模式: CGLIB創(chuàng)建的動(dòng)態(tài)代理對(duì)象比JDK創(chuàng)建的動(dòng)態(tài)代理對(duì)象的性能更高,但是CGLIB創(chuàng)建代理對(duì)象時(shí)所花費(fèi)的時(shí)間卻比JDK多得多。所以對(duì)于單例的對(duì)象,因?yàn)闊o(wú)需頻繁創(chuàng)建對(duì)象,用CGLIB合適,反之使用JDK方式要更為合適一些。同時(shí)由于CGLib由于是采用動(dòng)態(tài)創(chuàng)建子類的方法,對(duì)于final修飾的方法無(wú)法進(jìn)行代理。

擴(kuò)展知識(shí)

這里擴(kuò)展一個(gè)知識(shí)點(diǎn),那就是Spring AOP的底層實(shí)現(xiàn),為什么在這里提及呢?因?yàn)镾pring AOP的底層實(shí)現(xiàn)就是基于代理模式,而JDK 動(dòng)態(tài)代理和 CGLIB 動(dòng)態(tài)代理均是實(shí)現(xiàn) Spring AOP 的基礎(chǔ)。我們可以看下AOP的部分底層源碼:

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {@Overridepublic AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {Class<?> targetClass = config.getTargetClass();if (targetClass == null) {throw new AopConfigException("TargetSource cannot determine target class: " +"Either an interface or a target is required for proxy creation.");}// 判斷目標(biāo)類是否是接口或者目標(biāo)類是否Proxy類型,若是則使用JDK動(dòng)態(tài)代理if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {return new JdkDynamicAopProxy(config);}// 使用CGLIB的方式創(chuàng)建代理對(duì)象return new ObjenesisCglibAopProxy(config);}else {// 上面條件都不滿足就使用JDK的提供的代理方式生成代理對(duì)象return new JdkDynamicAopProxy(config);}} }

源碼的判斷邏輯并不難,主要是根據(jù)目標(biāo)類是否是接口或者Proxy類型來(lái)判斷使用哪種代理模式創(chuàng)建代理對(duì)象,使用的代理模式正是JDK動(dòng)態(tài)代理和CGLIB 動(dòng)態(tài)代理技術(shù)。由此可見(jiàn),了解代理模式還是很重要的,起碼以后面試官問(wèn)AOP的底層實(shí)現(xiàn)時(shí),我們還能吹一波呢,哈哈~~~

轉(zhuǎn)載于:https://www.cnblogs.com/yeya/p/11169014.html

總結(jié)

以上是生活随笔為你收集整理的设计模式:代理模式是什么,Spring AOP还和它有关系?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。