在開始之前,我們先把需要的jar包添加到工程里。新增maven依賴如下:
1
2
3
4
|
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-aop</artifactid> </dependency> |
接下來,我們進入正題。這里的涉及的通知類型有:前置通知、后置最終通知、后置返回通知、后置異常通知、環繞通知,下面我們就具體的來看一下怎么在springboot中添加這些通知。
首先我們先創建一個aspect切面類:
1
2
3
4
5
|
@component @aspect public class webcontrolleraop { } |
指定切點:
1
2
3
4
5
|
//匹配com.zkn.learnspringboot.web.controller包及其子包下的所有類的所有方法 @pointcut ( "execution(* com.zkn.learnspringboot.web.controller..*.*(..))" ) public void executeservice(){ } |
接著我們再創建一個controller請求處理類:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package com.zkn.learnspringboot.web.controller; import org.springframework.web.bind.annotation.requestmapping; import org.springframework.web.bind.annotation.restcontroller; /** * created by zkn on 2016/11/19. */ @restcontroller @requestmapping ( "/aop" ) public class aoptestcontroller { } |
前置通知
配置前置通知:
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
|
/** * 前置通知,方法調用前被調用 * @param joinpoint */ @before ( "executeservice()" ) public void dobeforeadvice(joinpoint joinpoint){ system.out.println( "我是前置通知!!!" ); //獲取目標方法的參數信息 object[] obj = joinpoint.getargs(); //aop代理類的信息 joinpoint.getthis(); //代理的目標對象 joinpoint.gettarget(); //用的最多 通知的簽名 signature signature = joinpoint.getsignature(); //代理的是哪一個方法 system.out.println(signature.getname()); //aop代理類的名字 system.out.println(signature.getdeclaringtypename()); //aop代理類的類(class)信息 signature.getdeclaringtype(); //獲取requestattributes requestattributes requestattributes = requestcontextholder.getrequestattributes(); //從獲取requestattributes中獲取httpservletrequest的信息 httpservletrequest request = (httpservletrequest) requestattributes.resolvereference(requestattributes.reference_request); //如果要獲取session信息的話,可以這樣寫: //httpsession session = (httpsession) requestattributes.resolvereference(requestattributes.reference_session); enumeration<string> enumeration = request.getparameternames(); map<string,string> parametermap = maps.newhashmap(); while (enumeration.hasmoreelements()){ string parameter = enumeration.nextelement(); parametermap.put(parameter,request.getparameter(parameter)); } string str = json.tojsonstring(parametermap); if (obj.length > 0 ) { system.out.println( "請求的參數信息為:" +str); } } |
注意:這里用到了joinpoint和requestcontextholder。通過joinpoint可以獲得通知的簽名信息,如目標方法名、目標方法參數信息等。通過requestcontextholder來獲取請求信息,session信息。
接下來我們在controller類里添加一個請求處理方法來測試一下前置通知:
1
2
3
4
5
|
@requestmapping ( "/testbeforeservice.do" ) public string testbeforeservice(string key,string value){ return "key=" +key+ " value=" +value; } |
前置通知攔截結果如下所示:
后置返回通知
配置后置返回通知的代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/** * 后置返回通知 * 這里需要注意的是: * 如果參數中的第一個參數為joinpoint,則第二個參數為返回值的信息 * 如果參數中的第一個參數不為joinpoint,則第一個參數為returning中對應的參數 * returning 限定了只有目標方法返回值與通知方法相應參數類型時才能執行后置返回通知,否則不執行,對于returning對應的通知方法參數為object類型將匹配任何目標返回值 * @param joinpoint * @param keys */ @afterreturning (value = "execution(* com.zkn.learnspringboot.web.controller..*.*(..))" ,returning = "keys" ) public void doafterreturningadvice1(joinpoint joinpoint,object keys){ system.out.println( "第一個后置返回通知的返回值:" +keys); } @afterreturning (value = "execution(* com.zkn.learnspringboot.web.controller..*.*(..))" ,returning = "keys" ,argnames = "keys" ) public void doafterreturningadvice2(string keys){ system.out.println( "第二個后置返回通知的返回值:" +keys); } |
controller里添加響應的請求處理信息來測試后置返回通知:
1
2
3
4
5
6
7
8
9
10
|
@requestmapping ( "/testafterreturning.do" ) public string testafterreturning(string key){ return "key=: " +key; } @requestmapping ( "/testafterreturning01.do" ) public integer testafterreturning01(integer key){ return key; } |
當發送請求為:http://localhost:8001/aop/testafterreturning.do?key=testsss&value=855sss時,處理結果如圖所示:
當發送請求為:http://localhost:8001/aop/testafterreturning01.do?key=55553&value=855sss時,處理結果如圖所示:
后置異常通知
后置異常通知的配置方式如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/** * 后置異常通知 * 定義一個名字,該名字用于匹配通知實現方法的一個參數名,當目標方法拋出異常返回后,將把目標方法拋出的異常傳給通知方法; * throwing 限定了只有目標方法拋出的異常與通知方法相應參數異常類型時才能執行后置異常通知,否則不執行, * 對于throwing對應的通知方法參數為throwable類型將匹配任何異常。 * @param joinpoint * @param exception */ @afterthrowing (value = "executeservice()" ,throwing = "exception" ) public void doafterthrowingadvice(joinpoint joinpoint,throwable exception){ //目標方法名: system.out.println(joinpoint.getsignature().getname()); if (exception instanceof nullpointerexception){ system.out.println( "發生了空指針異常!!!!!" ); } } |
controller里配置響應的請求處理類:
1
2
3
4
5
|
@requestmapping ( "/testafterthrowing.do" ) public string testafterthrowing(string key){ throw new nullpointerexception(); } |
后置異常通知方法的處理結果如下所示:
后置最終通知
后置最終通知的配置方式如下:
1
2
3
4
5
6
7
8
9
|
/** * 后置最終通知(目標方法只要執行完了就會執行后置通知方法) * @param joinpoint */ @after ( "executeservice()" ) public void doafteradvice(joinpoint joinpoint){ system.out.println( "后置通知執行了!!!!" ); } |
controller類配置相應的請求處理類:
1
2
3
4
5
6
7
8
9
10
|
@requestmapping ( "/testafter.do" ) public string testafter(string key){ throw new nullpointerexception(); } @requestmapping ( "/testafter02.do" ) public string testafter02(string key){ return key; } |
當發送請求為:http://localhost:8001/aop/testafter.do?key=55553&value=855sss
當發送請求為:http://localhost:8001/aop/testafter02.do?key=55553&value=855sss
環繞通知
環繞通知的配置方式如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/** * 環繞通知: * 環繞通知非常強大,可以決定目標方法是否執行,什么時候執行,執行時是否需要替換方法參數,執行完畢是否需要替換返回值。 * 環繞通知第一個參數必須是org.aspectj.lang.proceedingjoinpoint類型 */ @around ( "execution(* com.zkn.learnspringboot.web.controller..*.testaround*(..))" ) public object doaroundadvice(proceedingjoinpoint proceedingjoinpoint){ system.out.println( "環繞通知的目標方法名:" +proceedingjoinpoint.getsignature().getname()); try { object obj = proceedingjoinpoint.proceed(); return obj; } catch (throwable throwable) { throwable.printstacktrace(); } return null ; } |
controller對應的請求處理類如下:
1
2
3
4
5
|
@requestmapping ( "/testaroundservice.do" ) public string testaroundservice(string key){ return "環繞通知:" +key; } |
當發送請求為:http://localhost:8001/aop/testaroundservice.do?key=55553
當發送請求為:http://localhost:8001/aop/testafter02.do?key=55553&value=855sss時,不符合環繞通知的切入規則,所以環繞通知不會 執行。
完整的aop配置代碼如下:
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
package com.zkn.learnspringboot.aop; import com.alibaba.fastjson.json; import com.google.common.collect.maps; import org.aspectj.lang.joinpoint; import org.aspectj.lang.proceedingjoinpoint; import org.aspectj.lang.signature; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.component; import org.springframework.web.context.request.requestattributes; import org.springframework.web.context.request.requestcontextholder; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpsession; import java.util.enumeration; import java.util.map; /** * created by zkn on 2016/11/18. */ @component @aspect public class webcontrolleraop { //匹配com.zkn.learnspringboot.web.controller包及其子包下的所有類的所有方法 @pointcut ( "execution(* com.zkn.learnspringboot.web.controller..*.*(..))" ) public void executeservice(){ } /** * 前置通知,方法調用前被調用 * @param joinpoint */ @before ( "executeservice()" ) public void dobeforeadvice(joinpoint joinpoint){ system.out.println( "我是前置通知!!!" ); //獲取目標方法的參數信息 object[] obj = joinpoint.getargs(); //aop代理類的信息 joinpoint.getthis(); //代理的目標對象 joinpoint.gettarget(); //用的最多 通知的簽名 signature signature = joinpoint.getsignature(); //代理的是哪一個方法 system.out.println(signature.getname()); //aop代理類的名字 system.out.println(signature.getdeclaringtypename()); //aop代理類的類(class)信息 signature.getdeclaringtype(); //獲取requestattributes requestattributes requestattributes = requestcontextholder.getrequestattributes(); //從獲取requestattributes中獲取httpservletrequest的信息 httpservletrequest request = (httpservletrequest) requestattributes.resolvereference(requestattributes.reference_request); //如果要獲取session信息的話,可以這樣寫: //httpsession session = (httpsession) requestattributes.resolvereference(requestattributes.reference_session); enumeration<string> enumeration = request.getparameternames(); map<string,string> parametermap = maps.newhashmap(); while (enumeration.hasmoreelements()){ string parameter = enumeration.nextelement(); parametermap.put(parameter,request.getparameter(parameter)); } string str = json.tojsonstring(parametermap); if (obj.length > 0 ) { system.out.println( "請求的參數信息為:" +str); } } /** * 后置返回通知 * 這里需要注意的是: * 如果參數中的第一個參數為joinpoint,則第二個參數為返回值的信息 * 如果參數中的第一個參數不為joinpoint,則第一個參數為returning中對應的參數 * returning 限定了只有目標方法返回值與通知方法相應參數類型時才能執行后置返回通知,否則不執行,對于returning對應的通知方法參數為object類型將匹配任何目標返回值 * @param joinpoint * @param keys */ @afterreturning (value = "execution(* com.zkn.learnspringboot.web.controller..*.*(..))" ,returning = "keys" ) public void doafterreturningadvice1(joinpoint joinpoint,object keys){ system.out.println( "第一個后置返回通知的返回值:" +keys); } @afterreturning (value = "execution(* com.zkn.learnspringboot.web.controller..*.*(..))" ,returning = "keys" ,argnames = "keys" ) public void doafterreturningadvice2(string keys){ system.out.println( "第二個后置返回通知的返回值:" +keys); } /** * 后置異常通知 * 定義一個名字,該名字用于匹配通知實現方法的一個參數名,當目標方法拋出異常返回后,將把目標方法拋出的異常傳給通知方法; * throwing 限定了只有目標方法拋出的異常與通知方法相應參數異常類型時才能執行后置異常通知,否則不執行, * 對于throwing對應的通知方法參數為throwable類型將匹配任何異常。 * @param joinpoint * @param exception */ @afterthrowing (value = "executeservice()" ,throwing = "exception" ) public void doafterthrowingadvice(joinpoint joinpoint,throwable exception){ //目標方法名: system.out.println(joinpoint.getsignature().getname()); if (exception instanceof nullpointerexception){ system.out.println( "發生了空指針異常!!!!!" ); } } /** * 后置最終通知(目標方法只要執行完了就會執行后置通知方法) * @param joinpoint */ @after ( "executeservice()" ) public void doafteradvice(joinpoint joinpoint){ system.out.println( "后置通知執行了!!!!" ); } /** * 環繞通知: * 環繞通知非常強大,可以決定目標方法是否執行,什么時候執行,執行時是否需要替換方法參數,執行完畢是否需要替換返回值。 * 環繞通知第一個參數必須是org.aspectj.lang.proceedingjoinpoint類型 */ @around ( "execution(* com.zkn.learnspringboot.web.controller..*.testaround*(..))" ) public object doaroundadvice(proceedingjoinpoint proceedingjoinpoint){ system.out.println( "環繞通知的目標方法名:" +proceedingjoinpoint.getsignature().getname()); try { //obj之前可以寫目標方法執行前的邏輯 object obj = proceedingjoinpoint.proceed(); //調用執行目標方法 return obj; } catch (throwable throwable) { throwable.printstacktrace(); } return null ; } } |
完整的controller類代碼如下:
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
44
45
46
47
48
|
package com.zkn.learnspringboot.web.controller; import org.springframework.web.bind.annotation.requestmapping; import org.springframework.web.bind.annotation.restcontroller; /** * created by zkn on 2016/11/19. */ @restcontroller @requestmapping ( "/aop" ) public class aoptestcontroller { @requestmapping ( "/testbeforeservice.do" ) public string testbeforeservice(string key,string value){ return "key=" +key+ " value=" +value; } @requestmapping ( "/testafterreturning.do" ) public string testafterreturning(string key){ return "key=: " +key; } @requestmapping ( "/testafterreturning01.do" ) public integer testafterreturning01(integer key){ return key; } @requestmapping ( "/testafterthrowing.do" ) public string testafterthrowing(string key){ throw new nullpointerexception(); } @requestmapping ( "/testafter.do" ) public string testafter(string key){ throw new nullpointerexception(); } @requestmapping ( "/testafter02.do" ) public string testafter02(string key){ return key; } @requestmapping ( "/testaroundservice.do" ) public string testaroundservice(string key){ return "環繞通知:" +key; } } |
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:http://blog.csdn.net/zknxx/article/details/53240959