什么是代理?
為某一個對象創(chuàng)建一個代理對象,程序不直接用原本的對象,而是由創(chuàng)建的代理對象來控制原對象,通過代理類這中間一層,能有效控制對委托類對象的直接訪問,也可以很好地隱藏和保護委托類對象,同時也為實施不同控制策略預留了空間
什么是靜態(tài)代理?
由程序創(chuàng)建或特定工具自動生成源代碼,在程序運行前,代理類的.class文件就已經(jīng)存在
通過將目標類與代理類實現(xiàn)同一個接口,讓代理類持有真實類對象,然后在代理類方法中調(diào)用真實類方法,在調(diào)用真實類方法的前后添加我們所需要的功能擴展代碼來達到增強的目的。
優(yōu)點
- 代理使客戶端不需要知道實現(xiàn)類是什么,怎么做,而客戶端只需知道代理即可
- 方便增加功能,擴展業(yè)務邏輯
缺點
- 代理類中常出現(xiàn)大量冗余的代碼,非常不利于擴展和維護
- 如果接口增加一個方法,除了所有實現(xiàn)類需要實現(xiàn)這個方法外,所有代理類也需要實現(xiàn)此方法。增加了代碼維護的復雜度
案例演示
PayService.java(接口)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package net.cybclass.sp.proxy; public interface PayService { /** * 支付回調(diào) * @param outTradeNo 訂單號 * @return */ String callback(String outTradeNo); /** * 下單 * @param userId 用戶id * @param productId 產(chǎn)品id * @return */ int save( int userId, int productId); } |
PayServiceImpl.java(接口實現(xiàn)類)
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package net.cybclass.sp.proxy; public class PayServiceImpl implements PayService{ public String callback(String outTradeNo) { System.out.println( "目標類 PayServiceImpl 回調(diào) 方法 callback" ); return outTradeNo; } public int save( int userId, int productId) { System.out.println( "目標類 PayServiceImpl 回調(diào) 方法 save" ); return productId; } } |
StaticProxyPayServiceImpl.java(接口實現(xiàn)類,靜態(tài)代理)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package net.cybclass.sp.proxy; public class StaticProxyPayServiceImpl implements PayService{ private PayService payService; public StaticProxyPayServiceImpl(PayService payService) { this .payService=payService; } public String callback(String outTradeNo) { System.out.println( "StaticProxyPayServiceImpl callback begin" ); String result=payService.callback(outTradeNo); System.out.println( "StaticProxyPayServiceImpl callback end" ); return result; } public int save( int userId, int productId) { System.out.println( "StaticProxyPayServiceImpl save begin" ); int id = payService.save(userId, productId); System.out.println( "StaticProxyPayServiceImpl save end" ); return id; } } |
演示
什么是動態(tài)代理?
在程序運行時,運用反射機制動態(tài)創(chuàng)建而成,無需手動編寫代碼
JDK動態(tài)代理
CGLIB動態(tài)代理(原理:是對指定的業(yè)務類生成一個子類,并覆蓋其中的業(yè)務方法來實現(xiàn)代理)
jdk動態(tài)代理演示
1
2
3
4
5
6
|
定義一個類,去實現(xiàn)InvocationHandler這個接口,并車從寫invoke方法 //Object proxy:被代理的對象 //Method method:要調(diào)用的方法 //Object[] args:方法調(diào)用時所需要參數(shù) public Object invoke(Object proxy, Method method, Object[] args){} |
PayService.java(接口)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package net.cybclass.sp.proxy; public interface PayService { /** * 支付回調(diào) * @param outTradeNo 訂單號 * @return */ String callback(String outTradeNo); /** * 下單 * @param userId 用戶id * @param productId 產(chǎn)品id * @return */ int save( int userId, int productId); } |
PayServiceImpl.java(接口實現(xiàn)類)
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package net.cybclass.sp.proxy; public class PayServiceImpl implements PayService{ public String callback(String outTradeNo) { System.out.println( "目標類 PayServiceImpl 回調(diào) 方法 callback" ); return outTradeNo; } public int save( int userId, int productId) { System.out.println( "目標類 PayServiceImpl 回調(diào) 方法 save" ); return productId; } } |
JDKProxy.java(jdk動態(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
38
39
40
41
42
43
|
package net.cybclass.sp.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class JDKProxy implements InvocationHandler { //目標類 private Object targetObject; /** * 獲取代理對象 * @param targetObject 目標類 * @return */ public Object newProxyInstance(Object targetObject) { this .targetObject = targetObject; //綁定關(guān)系,也就是和具體的那個實現(xiàn)類關(guān)聯(lián) return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this ); } /** * JDK動態(tài)代理 * * @param proxy 靜態(tài)代理對象 * @param method 要調(diào)用的方法 * @param args 方法調(diào)用時所需要參數(shù) * @return * @throws Throwable */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null ; try { System.out.println( "通過JDK動態(tài)代理調(diào)用" +method.getName()+ ",打印日志 begin" ); result = method.invoke(targetObject, args); System.out.println( "通過JDK動態(tài)代理調(diào)用" +method.getName()+ ",打印日志 end" ); } catch (Exception ex) { ex.printStackTrace(); } return result; } } |
CGLIB動態(tài)代理演示
PayService.java(接口)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package net.cybclass.sp.proxy; public interface PayService { /** * 支付回調(diào) * @param outTradeNo 訂單號 * @return */ String callback(String outTradeNo); /** * 下單 * @param userId 用戶id * @param productId 產(chǎn)品id * @return */ int save( int userId, int productId); } |
PayServiceImpl.java(接口實現(xiàn)類)
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package net.cybclass.sp.proxy; public class PayServiceImpl implements PayService{ public String callback(String outTradeNo) { System.out.println( "目標類 PayServiceImpl 回調(diào) 方法 callback" ); return outTradeNo; } public int save( int userId, int productId) { System.out.println( "目標類 PayServiceImpl 回調(diào) 方法 save" ); return productId; } } |
CGLIBProxy.java(CGLIB動態(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
|
package net.cybclass.sp.proxy; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class CGLIBProxy implements MethodInterceptor { //目標類 private Object targetObject; //綁定關(guān)系 public Object newProxyInstance(Object targetObject){ this .targetObject=targetObject; Enhancer enhancer= new Enhancer(); //設置代理類的父類(目標類) enhancer.setSuperclass( this .targetObject.getClass()); //設置回調(diào)函數(shù) enhancer.setCallback( this ); //創(chuàng)建子類(代理對象) return enhancer.create(); } public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object result= null ; try { System.out.println( "通過CGLIB動態(tài)代理調(diào)用" +method.getName()+ ",打印日志 begin" ); result=methodProxy.invokeSuper(o,args); System.out.println( "通過CGLIB動態(tài)代理調(diào)用" +method.getName()+ ",打印日志 end" ); } catch (Exception ex){ ex.printStackTrace(); } return result; } } |
總結(jié)
動態(tài)代理與靜態(tài)代理相比較,最大的好處是接口中聲明的所有方法都被轉(zhuǎn)移到調(diào)用處理器一個集中的方法中處理,解耦和易維護。
兩種動態(tài)代理的區(qū)別
- JDK動態(tài)代理:要求目標對象實現(xiàn)一個接口,但是有時候目標對象只是一個單獨的對象,并沒有實現(xiàn)任何的接口,這個時候就可以用CGLIB動態(tài)代理
- JDK動態(tài)代理是自帶的,CGLIB需要引入第三方包
- CGLIB動態(tài)代理,它是內(nèi)存中構(gòu)建一個子類對象從而實現(xiàn)對目標對象功能的擴展
- CGLIB動態(tài)代理基于繼承來實現(xiàn)代理,所以無法對final類,private方法和static方法實現(xiàn)代理
Spring AOP中的代理使用的默認策略
- 如果目標對象實現(xiàn)類接口,則默認采用JDK動態(tài)代理
- 如果目標對象沒有實現(xiàn)接口,則采用CGLIB進行動態(tài)代理
到此這篇關(guān)于 Spring AOP里的靜態(tài)代理和動態(tài)代理用法詳解的文章就介紹到這了,更多相關(guān) Spring AOP 靜態(tài)代理 動態(tài)代理內(nèi)容請搜索服務器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務器之家!
原文鏈接:https://www.cnblogs.com/chenyanbin/p/13306055.html