您好,登錄后才能下訂單哦!
一、動(dòng)態(tài)代理概念
動(dòng)態(tài)代理分為JDK動(dòng)態(tài)代理和cglib動(dòng)態(tài)代理兩種方式。
jdk動(dòng)態(tài)代理是由Java內(nèi)部的反射機(jī)制來(lái)實(shí)現(xiàn)的,cglib動(dòng)態(tài)代理底層則是借助asm來(lái)實(shí)現(xiàn)的。
總的來(lái)說(shuō),反射機(jī)制在生成類的過(guò)程中比較高效,而asm在生成類之后的相關(guān)執(zhí)行過(guò)程中比較高效(可以通過(guò)將asm生成的類進(jìn)行緩存,這樣解決asm生成類過(guò)程低效問(wèn)題)。
還有一點(diǎn)必須注意:jdk動(dòng)態(tài)代理的應(yīng)用前提,必須是目標(biāo)類基于統(tǒng)一的接口。如果沒(méi)有上述前提,jdk動(dòng)態(tài)代理不能應(yīng)用。
由此可以看出,jdk動(dòng)態(tài)代理有一定的局限性,cglib這種第三方類庫(kù)實(shí)現(xiàn)的動(dòng)態(tài)代理應(yīng)用更加廣泛,且在效率上更有優(yōu)勢(shì)。
二、JDK動(dòng)態(tài)代理
以下代碼使用代理模式實(shí)現(xiàn)一個(gè)大小寫字符轉(zhuǎn)換的功能。
定義接口和實(shí)現(xiàn)類:
ISomeService接口:
package com.ietree.basicskill.designpattern.dynamicproxy.jdk; /** * 接口類 * * @author Root */ public interface ISomeService { String doFirst(); void doSecond(); }
SomeServiceImpl實(shí)現(xiàn)類:
package com.ietree.basicskill.designpattern.dynamicproxy.jdk; /** * 實(shí)現(xiàn)類 * * @author Root */ public class SomeServiceImpl implements ISomeService { @Override public String doFirst() { System.out.println("執(zhí)行doFirst()..."); String result = "abcde"; return result; } @Override public void doSecond() { System.out.println("執(zhí)行doSecond()..."); } }
JDK動(dòng)態(tài)代理類:
package com.ietree.basicskill.designpattern.dynamicproxy.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class Main { public static void main(String[] args) { final ISomeService target = new SomeServiceImpl(); // 使用JDK的Proxy動(dòng)態(tài)代理,要求目標(biāo)類和代理類必須實(shí)現(xiàn)相同的接口,因?yàn)槠涞讓拥膱?zhí)行原理與靜態(tài)代理的相同 ISomeService service = (ISomeService) Proxy.newProxyInstance( // 目標(biāo)類的類加載器 target.getClass().getClassLoader(), // 目標(biāo)類所實(shí)現(xiàn)的所有接口 target.getClass().getInterfaces(), new InvocationHandler() { // proxy:代理對(duì)象 // method:目標(biāo)方法 // args:目標(biāo)方法的參數(shù)列表 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 調(diào)用目標(biāo)方法 Object result = method.invoke(target, args); if (result != null) { result = ((String) result).toUpperCase(); } return result; } }); String result = service.doFirst(); System.out.println(result); service.doSecond(); } }
三、cglib動(dòng)態(tài)代理
Cglib是一個(gè)優(yōu)秀的動(dòng)態(tài)代理框架,它的底層使用ASM在內(nèi)存中動(dòng)態(tài)的生成被代理類的子類,使用CGLIB即使代理類沒(méi)有實(shí)現(xiàn)任何接口也可以實(shí)現(xiàn)動(dòng)態(tài)代理功能。CGLIB具有簡(jiǎn)單易用,它的運(yùn)行速度要遠(yuǎn)遠(yuǎn)快于JDK的Proxy動(dòng)態(tài)代理:
CGLIB的核心類:
net.sf.cglib.proxy.Enhancer – 主要的增強(qiáng)類
net.sf.cglib.proxy.MethodInterceptor – 主要的方法攔截類,它是Callback接口的子接口,需要用戶實(shí)現(xiàn)
net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method類的代理類,可以方便的實(shí)現(xiàn)對(duì)源對(duì)象方法的調(diào)用,如使用:
Object o = methodProxy.invokeSuper(proxy, args);//雖然第一個(gè)參數(shù)是被代理對(duì)象,也不會(huì)出現(xiàn)死循環(huán)的問(wèn)題。
net.sf.cglib.proxy.MethodInterceptor接口是最通用的回調(diào)(callback)類型,它經(jīng)常被基于代理的AOP用來(lái)實(shí)現(xiàn)攔截(intercept)方法的調(diào)用。這個(gè)接口只定義了一個(gè)方法
public Object intercept(Object object, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable;
第一個(gè)參數(shù)是代理對(duì)像,第二和第三個(gè)參數(shù)分別是攔截的方法和方法的參數(shù)。原來(lái)的方法可能通過(guò)使用java.lang.reflect.Method對(duì)象的一般反射調(diào)用,或者使用 net.sf.cglib.proxy.MethodProxy對(duì)象調(diào)用。net.sf.cglib.proxy.MethodProxy通常被首選使用,因?yàn)樗臁?/p>
以下程序?qū)崿F(xiàn)了大小寫轉(zhuǎn)換的功能:
實(shí)現(xiàn)類SomeService:
package com.ietree.basicskill.designpattern.dynamicproxy.cglib; /** * 實(shí)現(xiàn)類 * * @author Root */ public class SomeService { public String doFirst() { System.out.println("執(zhí)行doFirst()..."); String result = "abcde"; return result; } public void doSecond() { System.out.println("執(zhí)行doSecond()..."); } }
代理類MyCglibFactory:
package com.ietree.basicskill.designpattern.dynamicproxy.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class MyCglibFactory implements MethodInterceptor { private SomeService target; public MyCglibFactory() { super(); target = new SomeService(); } public SomeService myCglibCreator() { // 創(chuàng)建增強(qiáng)器對(duì)象 Enhancer enhancer = new Enhancer(); // 指定目標(biāo)類,即父類 enhancer.setSuperclass(SomeService.class); // 設(shè)置回調(diào)接口對(duì)象 enhancer.setCallback(this); return (SomeService) enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // 調(diào)用目標(biāo)方法 Object result = method.invoke(target, args); if (result != null) { result = ((String) result).toUpperCase(); } return result; } }
測(cè)試:
package com.ietree.basicskill.designpattern.dynamicproxy.cglib; public class Main { public static void main(String[] args) { SomeService service = new MyCglibFactory().myCglibCreator(); String result = service.doFirst(); System.out.println("result = " + result); service.doSecond(); } }
運(yùn)行結(jié)果:
執(zhí)行doFirst()... result = ABCDE 執(zhí)行doSecond()...
以上這篇老生常談設(shè)計(jì)模式之動(dòng)態(tài)代理就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持億速云。
免責(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)容。