您好,登錄后才能下訂單哦!
這篇文章給大家介紹如何在Spring框架中實(shí)現(xiàn)動(dòng)態(tài)代理,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。
動(dòng)態(tài)代理,是一種通過(guò)運(yùn)行時(shí)操作字節(jié)碼,以達(dá)到增強(qiáng)類的功能的技術(shù),也是Spring AOP操作的基礎(chǔ),關(guān)于AOP的內(nèi)容,將在后面的筆記中詳細(xì)講解,本小節(jié)主要是理清楚動(dòng)態(tài)代理,畢竟,Spring的AOP是基于動(dòng)態(tài)代理技術(shù),對(duì)動(dòng)態(tài)代理技術(shù)有所了解,對(duì)于學(xué)習(xí)Spring AOP也會(huì)有幫助
動(dòng)態(tài)代理技術(shù)詳解
動(dòng)態(tài)代理,現(xiàn)在主要是用于增強(qiáng)類的功能,同時(shí)由于是具有動(dòng)態(tài)性,所以避免了需要頻繁創(chuàng)建類的操作,同時(shí),也使得原有的代碼在不需要改變的情況下,對(duì)類的功能進(jìn)行增強(qiáng),主要的動(dòng)態(tài)代理技術(shù)有:通過(guò)實(shí)現(xiàn)目標(biāo)接口,重寫(xiě)其方法,以增強(qiáng)其能力,典型的以JDK動(dòng)態(tài)代理為代表;或者,通過(guò)繼承類,重寫(xiě)其方法以增強(qiáng)其能力,典型的以CGLib為代表,這兩種技術(shù)分別從不同的方向來(lái)對(duì)類的能力進(jìn)行擴(kuò)充,接下來(lái)來(lái)具體看下這兩種技術(shù)的特點(diǎn)以及差異。
基于JDK動(dòng)態(tài)代理
基于JDK的動(dòng)態(tài)代理技術(shù),其主要特點(diǎn)就是目標(biāo)類,也就是需要被代理的類,必須有接口,并且代理類必須實(shí)現(xiàn)跟它一樣的接口,從而來(lái)起到代理其事務(wù)的功能,具體使用如下代碼所示,假設(shè)有一個(gè)UserService類,主要用于負(fù)責(zé)用戶的登錄和退出,同時(shí),有個(gè)日志類,負(fù)責(zé)記錄用戶的操作信息,直接將信息日志寫(xiě)在對(duì)應(yīng)的UserService實(shí)現(xiàn)類中,可以達(dá)到目的,但顯然這種方式不是很合理,特別是在UserService有很多個(gè)方法需要做日志記錄的時(shí)候,就會(huì)使得日志記錄代碼遍布整個(gè)UserService,不僅使得代碼的冗余很大,而且當(dāng)需要進(jìn)行修改的時(shí)候,也需要逐個(gè)修改,非常麻煩,這個(gè)時(shí)候,采用動(dòng)態(tài)代理技術(shù)就是一種非常好的方法了。
/** * UserService接口 */ interface UserService{ void login(); void logout(); } /** * UseService實(shí)現(xiàn)類 */ class UserServiceImpl implements UserService{ @Override public void login() { System.out.println("someone login...."); } @Override public void logout() { System.out.println("someone logout...."); } } /** * 實(shí)現(xiàn)InvocationHandle接口,用于織入所要增強(qiáng)的代碼 */ class UserServiceHandle implements InvocationHandler{ private UserService userService; public UserServiceHandle(UserService userService) { this.userService = userService; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { LogService.info(); Object object = method.invoke(userService, args); LogService.info(); return object; } } /** * 代理類工廠,用于產(chǎn)生UseService類的代理類 */ class ProxyFactory{ public static UserService getProxyObject(UserService userService){ // 使用JDK動(dòng)態(tài)代理技術(shù)來(lái)創(chuàng)建對(duì)應(yīng)的代理類 return (UserService) Proxy.newProxyInstance( userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), new UserServiceHandle(userService) ); } }
這樣,當(dāng)我們需要使用UseService類的時(shí)候,只需要從ProxyFactory中獲取即可,而且獲取的對(duì)象是UserService對(duì)象的代理類,也就是說(shuō),獲得的對(duì)象是UserService對(duì)象的增強(qiáng)版
基于CGLib的動(dòng)態(tài)代理技術(shù)
從上面的ProxyFactory工廠中可以看到,在使用JDK進(jìn)行創(chuàng)建動(dòng)態(tài)代理對(duì)象的時(shí)候,需要為其提供接口,或者說(shuō),如果所要增強(qiáng)的目標(biāo)類沒(méi)有實(shí)現(xiàn)任何接口,則JDK動(dòng)態(tài)代理技術(shù)是無(wú)法為其創(chuàng)建對(duì)應(yīng)的代理對(duì)象的,這是JDK動(dòng)態(tài)代理技術(shù)的一種缺點(diǎn),而CGLib動(dòng)態(tài)代理技術(shù)則恰好彌補(bǔ)了這個(gè)缺點(diǎn),CGLib動(dòng)態(tài)代理技術(shù)使用的是繼承該類的方式,從而避免了需要接口的缺陷,具體使用如下所示,注意,需要導(dǎo)入對(duì)應(yīng)的依賴文件
/** * 基于CGLib的動(dòng)態(tài)代理技術(shù) * 注意這里需要實(shí)現(xiàn)MethodInterceptor接口 */ class ProxyFactory implements MethodInterceptor{ // 提供對(duì)應(yīng)的增強(qiáng)操作類 private Enhancer enhancer = new Enhancer(); public UserService getProxyObject(Class clazz){ // 設(shè)置所要增強(qiáng)的類的父類 enhancer.setSuperclass(clazz); // 設(shè)置回調(diào)對(duì)象 enhancer.setCallback(this); // 創(chuàng)建對(duì)應(yīng)的對(duì)象 return (UserService) enhancer.create(); } // 實(shí)現(xiàn)攔截方法,用于攔截對(duì)應(yīng)的方法,并且對(duì)對(duì)應(yīng)的方法進(jìn)行增強(qiáng) // 參數(shù)含義:傳入的對(duì)象, Method對(duì)象,方法的參數(shù),進(jìn)行代理后的Method對(duì)象 @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { LogService.info(); // 這里需要注意,由于methodProxy對(duì)象是增強(qiáng)后的Method對(duì)象,所以這里需要調(diào)用的 // 是methodProxy父類的方法,也就是所以增強(qiáng)的類的方法,以實(shí)現(xiàn)原來(lái)的功能 Object object = methodProxy.invokeSuper(o, objects); LogService.info(); return object; } }
可以看到,使用CGLib動(dòng)態(tài)代理技術(shù)可以在不需要實(shí)現(xiàn)接口的情況下東塔為對(duì)象創(chuàng)建代理對(duì)象,在很大程度上彌補(bǔ)了JDK動(dòng)態(tài)代理技術(shù)的缺點(diǎn),不過(guò)由于CGLib動(dòng)態(tài)代理技術(shù)是采用繼承目標(biāo)類的方式,所以也存在一些問(wèn)題,比如說(shuō),對(duì)于final以及private修飾的方法是無(wú)法為其增強(qiáng)的,這里還需要注意一下。
總結(jié)
動(dòng)態(tài)代理技術(shù)是實(shí)現(xiàn)AOP技術(shù)的基礎(chǔ),也是一種很方便地實(shí)現(xiàn)方式,常用的動(dòng)態(tài)代理技術(shù)有基于JDK動(dòng)態(tài)代理技術(shù)以及基于CGLib的動(dòng)態(tài)代理技術(shù),兩種技術(shù)各有千秋,也都各有缺點(diǎn)基于JDK的動(dòng)態(tài)代理技術(shù)需要為其提供接口,基于CGLib的動(dòng)態(tài)代理技術(shù)不能為final以及private修飾的方法進(jìn)行增強(qiáng),在使用的時(shí)候需要根據(jù)具體進(jìn)行進(jìn)行合理選擇。
關(guān)于如何在Spring框架中實(shí)現(xiàn)動(dòng)態(tài)代理就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。