一、動(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ī)制來實(shí)現(xiàn)的,cglib動(dòng)態(tài)代理底層則是借助asm來實(shí)現(xiàn)的。
總的來說,反射機(jī)制在生成類的過程中比較高效,而asm在生成類之后的相關(guān)執(zhí)行過程中比較高效(可以通過將asm生成的類進(jìn)行緩存,這樣解決asm生成類過程低效問題)。
還有一點(diǎn)必須注意:jdk動(dòng)態(tài)代理的應(yīng)用前提,必須是目標(biāo)類基于統(tǒng)一的接口。如果沒有上述前提,jdk動(dòng)態(tài)代理不能應(yīng)用。
由此可以看出,jdk動(dòng)態(tài)代理有一定的局限性,cglib這種第三方類庫實(shí)現(xiàn)的動(dòng)態(tài)代理應(yīng)用更加廣泛,且在效率上更有優(yōu)勢。
二、JDK動(dòng)態(tài)代理
以下代碼使用代理模式實(shí)現(xiàn)一個(gè)大小寫字符轉(zhuǎn)換的功能。
定義接口和實(shí)現(xiàn)類:
ISomeService接口:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package com.ietree.basicskill.designpattern.dynamicproxy.jdk; /** * 接口類 * * @author Root */ public interface ISomeService { String doFirst(); void doSecond(); } |
SomeServiceImpl實(shí)現(xiàn)類:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
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)代理類:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
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:代理對象 // 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即使代理類沒有實(shí)現(xiàn)任何接口也可以實(shí)現(xiàn)動(dòng)態(tài)代理功能。CGLIB具有簡單易用,它的運(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)對源對象方法的調(diào)用,如使用:
Object o = methodProxy.invokeSuper(proxy, args);//雖然第一個(gè)參數(shù)是被代理對象,也不會(huì)出現(xiàn)死循環(huán)的問題。
net.sf.cglib.proxy.MethodInterceptor接口是最通用的回調(diào)(callback)類型,它經(jīng)常被基于代理的AOP用來實(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ù)是代理對像,第二和第三個(gè)參數(shù)分別是攔截的方法和方法的參數(shù)。原來的方法可能通過使用java.lang.reflect.Method對象的一般反射調(diào)用,或者使用 net.sf.cglib.proxy.MethodProxy對象調(diào)用。net.sf.cglib.proxy.MethodProxy通常被首選使用,因?yàn)樗臁?/p>
以下程序?qū)崿F(xiàn)了大小寫轉(zhuǎn)換的功能:
實(shí)現(xiàn)類SomeService:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
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)器對象 Enhancer enhancer = new Enhancer(); // 指定目標(biāo)類,即父類 enhancer.setSuperclass(SomeService. class ); // 設(shè)置回調(diào)接口對象 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; } } |
測試:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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é)果:
1
2
3
|
執(zhí)行doFirst()... result = ABCDE 執(zhí)行doSecond()... |
以上這篇老生常談設(shè)計(jì)模式之動(dòng)態(tài)代理就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持服務(wù)器之家。