AOP的攔截功能是由java中的動態代理來實現的。說白了,就是在目標類的基礎上增加切面邏輯,生成增強的目標類(該切面邏輯或者在目標類函數執行之前,或者目標類函數執行之后,或者在目標類函數拋出異常時候執行。不同的切入時機對應不同的Interceptor的種類,如BeforeAdviseInterceptor,AfterAdviseInterceptor以及ThrowsAdviseInterceptor等)。
那么動態代理是如何實現將切面邏輯(advise)織入到目標類方法中去的呢?下面我們就來詳細介紹并實現AOP中用到的兩種動態代理。
AOP的源碼中用到了兩種動態代理來實現攔截切入功能:jdk動態代理和cglib動態代理。兩種方法同時存在,各有優劣。jdk動態代理是由Java內部的反射機制來實現的,cglib動態代理底層則是借助asm來實現的。總的來說,反射機制在生成類的過程中比較高效,而asm在生成類之后的相關執行過程中比較高效(可以通過將asm生成的類進行緩存,這樣解決asm生成類過程低效問題)。還有一點必須注意:jdk動態代理的應用前提,必須是目標類基于統一的接口。如果沒有上述前提,jdk動態代理不能應用。由此可以看出,jdk動態代理有一定的局限性,cglib這種第三方類庫實現的動態代理應用更加廣泛,且在效率上更有優勢。。
1、定義接口和實現
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
|
package com.meituan.hyt.test3.service; public interface UserService { public String getName( int id); public Integer getAge( int id); } package com.meituan.hyt.test3.service.impl; import com.meituan.hyt.test3.service.UserService; public class UserServiceImpl implements UserService { @Override public String getName( int id) { System.out.println( "------getName------" ); return "Tom" ; } @Override public Integer getAge( int id) { System.out.println( "------getAge------" ); return 10 ; } } |
2、jdk動態代理實現
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
|
package com.meituan.hyt.test3.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyInvocationHandler implements InvocationHandler { private Object target; MyInvocationHandler() { super (); } MyInvocationHandler(Object target) { super (); this .target = target; } @Override public Object invoke(Object o, Method method, Object[] args) throws Throwable { if ( "getName" .equals(method.getName())){ System.out.println( "++++++before " + method.getName() + "++++++" ); Object result = method.invoke(target, args); System.out.println( "++++++after " + method.getName() + "++++++" ); return result; } else { Object result = method.invoke(target, args); return result; } } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package com.meituan.hyt.test3.jdk; import com.meituan.hyt.test3.service.UserService; import com.meituan.hyt.test3.service.impl.UserServiceImpl; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class Main1 { public static void main(String[] args) { UserService userService = new UserServiceImpl(); InvocationHandler invocationHandler = new MyInvocationHandler(userService); UserService userServiceProxy = (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), invocationHandler); System.out.println(userServiceProxy.getName( 1 )); System.out.println(userServiceProxy.getAge( 1 )); } } |
運行結果
1
2
3
4
5
6
|
++++++before getName++++++ ------getName------ ++++++after getName++++++ Tom ------getAge------ 10 |
3、cglib動態代理實現
Cglib是一個優秀的動態代理框架,它的底層使用ASM在內存中動態的生成被代理類的子類,使用CGLIB即使代理類沒有實現任何接口也可以實現動態代理功能。CGLIB具有簡單易用,它的運行速度要遠遠快于JDK的Proxy動態代理:
CGLIB的核心類:
1
2
3
4
5
6
7
8
|
net.sf.cglib.proxy.Enhancer – 主要的增強類 net.sf.cglib.proxy.MethodInterceptor – 主要的方法攔截類,它是Callback接口的子接口,需要用戶實現 net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method類的代理類,可以方便的實現對源對象方法的調用,如使用: Object o = methodProxy.invokeSuper(proxy, args); //雖然第一個參數是被代理對象,也不會出現死循環的問題。 net.sf.cglib.proxy.MethodInterceptor接口是最通用的回調(callback)類型,它經常被基于代理的AOP用來實現攔截(intercept)方法的調用。這個接口只定義了一個方法 public Object intercept(Object object, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable; |
第一個參數是代理對像,第二和第三個參數分別是攔截的方法和方法的參數。原來的方法可能通過使用java.lang.reflect.Method對象的一般反射調用,或者使用 net.sf.cglib.proxy.MethodProxy對象調用。net.sf.cglib.proxy.MethodProxy通常被首選使用,因為它更快。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package com.meituan.hyt.test3.cglib; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class CglibProxy implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println( "++++++before " + methodProxy.getSuperName() + "++++++" ); System.out.println(method.getName()); Object o1 = methodProxy.invokeSuper(o, args); System.out.println( "++++++before " + methodProxy.getSuperName() + "++++++" ); return o1; } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package com.meituan.hyt.test3.cglib; import com.meituan.hyt.test3.service.UserService; import com.meituan.hyt.test3.service.impl.UserServiceImpl; import net.sf.cglib.proxy.Enhancer; public class Main2 { public static void main(String[] args) { CglibProxy cglibProxy = new CglibProxy(); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserServiceImpl. class ); enhancer.setCallback(cglibProxy); UserService o = (UserService)enhancer.create(); o.getName( 1 ); o.getAge( 1 ); } } |
運行結果:
1
2
3
4
5
6
7
8
|
++++++before CGLIB$getName$ 0 ++++++ getName ------getName------ ++++++before CGLIB$getName$ 0 ++++++ ++++++before CGLIB$getAge$ 1 ++++++ getAge ------getAge------ ++++++before CGLIB$getAge$ 1 ++++++ |
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
原文鏈接:https://my.oschina.net/u/3346994/blog/873128