在開始之前,我們先把需要的jar包添加到工程里。新增maven依賴如下:
1
2
3
4
|
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-aop</artifactid> </dependency> |
接下來,我們進(jìn)入正題。這里的涉及的通知類型有:前置通知、后置最終通知、后置返回通知、后置異常通知、環(huán)繞通知,下面我們就具體的來看一下怎么在springboot中添加這些通知。
首先我們先創(chuàng)建一個(gè)aspect切面類:
1
2
3
4
5
|
@component @aspect public class webcontrolleraop { } |
指定切點(diǎn):
1
2
3
4
5
|
//匹配com.zkn.learnspringboot.web.controller包及其子包下的所有類的所有方法 @pointcut ( "execution(* com.zkn.learnspringboot.web.controller..*.*(..))" ) public void executeservice(){ } |
接著我們再創(chuàng)建一個(gè)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
|
/** * 前置通知,方法調(diào)用前被調(diào)用 * @param joinpoint */ @before ( "executeservice()" ) public void dobeforeadvice(joinpoint joinpoint){ system.out.println( "我是前置通知!!!" ); //獲取目標(biāo)方法的參數(shù)信息 object[] obj = joinpoint.getargs(); //aop代理類的信息 joinpoint.getthis(); //代理的目標(biāo)對象 joinpoint.gettarget(); //用的最多 通知的簽名 signature signature = joinpoint.getsignature(); //代理的是哪一個(gè)方法 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( "請求的參數(shù)信息為:" +str); } } |
注意:這里用到了joinpoint和requestcontextholder。通過joinpoint可以獲得通知的簽名信息,如目標(biāo)方法名、目標(biāo)方法參數(shù)信息等。通過requestcontextholder來獲取請求信息,session信息。
接下來我們在controller類里添加一個(gè)請求處理方法來測試一下前置通知:
1
2
3
4
5
|
@requestmapping ( "/testbeforeservice.do" ) public string testbeforeservice(string key,string value){ return "key=" +key+ " value=" +value; } |
前置通知攔截結(jié)果如下所示:
后置返回通知
配置后置返回通知的代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/** * 后置返回通知 * 這里需要注意的是: * 如果參數(shù)中的第一個(gè)參數(shù)為joinpoint,則第二個(gè)參數(shù)為返回值的信息 * 如果參數(shù)中的第一個(gè)參數(shù)不為joinpoint,則第一個(gè)參數(shù)為returning中對應(yīng)的參數(shù) * returning 限定了只有目標(biāo)方法返回值與通知方法相應(yīng)參數(shù)類型時(shí)才能執(zhí)行后置返回通知,否則不執(zhí)行,對于returning對應(yīng)的通知方法參數(shù)為object類型將匹配任何目標(biāo)返回值 * @param joinpoint * @param keys */ @afterreturning (value = "execution(* com.zkn.learnspringboot.web.controller..*.*(..))" ,returning = "keys" ) public void doafterreturningadvice1(joinpoint joinpoint,object keys){ system.out.println( "第一個(gè)后置返回通知的返回值:" +keys); } @afterreturning (value = "execution(* com.zkn.learnspringboot.web.controller..*.*(..))" ,returning = "keys" ,argnames = "keys" ) public void doafterreturningadvice2(string keys){ system.out.println( "第二個(gè)后置返回通知的返回值:" +keys); } |
controller里添加響應(yīng)的請求處理信息來測試后置返回通知:
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; } |
當(dāng)發(fā)送請求為:http://localhost:8001/aop/testafterreturning.do?key=testsss&value=855sss時(shí),處理結(jié)果如圖所示:
當(dāng)發(fā)送請求為:http://localhost:8001/aop/testafterreturning01.do?key=55553&value=855sss時(shí),處理結(jié)果如圖所示:
后置異常通知
后置異常通知的配置方式如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/** * 后置異常通知 * 定義一個(gè)名字,該名字用于匹配通知實(shí)現(xiàn)方法的一個(gè)參數(shù)名,當(dāng)目標(biāo)方法拋出異常返回后,將把目標(biāo)方法拋出的異常傳給通知方法; * throwing 限定了只有目標(biāo)方法拋出的異常與通知方法相應(yīng)參數(shù)異常類型時(shí)才能執(zhí)行后置異常通知,否則不執(zhí)行, * 對于throwing對應(yīng)的通知方法參數(shù)為throwable類型將匹配任何異常。 * @param joinpoint * @param exception */ @afterthrowing (value = "executeservice()" ,throwing = "exception" ) public void doafterthrowingadvice(joinpoint joinpoint,throwable exception){ //目標(biāo)方法名: system.out.println(joinpoint.getsignature().getname()); if (exception instanceof nullpointerexception){ system.out.println( "發(fā)生了空指針異常!!!!!" ); } } |
controller里配置響應(yīng)的請求處理類:
1
2
3
4
5
|
@requestmapping ( "/testafterthrowing.do" ) public string testafterthrowing(string key){ throw new nullpointerexception(); } |
后置異常通知方法的處理結(jié)果如下所示:
后置最終通知
后置最終通知的配置方式如下:
1
2
3
4
5
6
7
8
9
|
/** * 后置最終通知(目標(biāo)方法只要執(zhí)行完了就會(huì)執(zhí)行后置通知方法) * @param joinpoint */ @after ( "executeservice()" ) public void doafteradvice(joinpoint joinpoint){ system.out.println( "后置通知執(zhí)行了!!!!" ); } |
controller類配置相應(yīng)的請求處理類:
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; } |
當(dāng)發(fā)送請求為:http://localhost:8001/aop/testafter.do?key=55553&value=855sss
當(dāng)發(fā)送請求為:http://localhost:8001/aop/testafter02.do?key=55553&value=855sss
環(huán)繞通知
環(huán)繞通知的配置方式如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/** * 環(huán)繞通知: * 環(huán)繞通知非常強(qiáng)大,可以決定目標(biāo)方法是否執(zhí)行,什么時(shí)候執(zhí)行,執(zhí)行時(shí)是否需要替換方法參數(shù),執(zhí)行完畢是否需要替換返回值。 * 環(huán)繞通知第一個(gè)參數(shù)必須是org.aspectj.lang.proceedingjoinpoint類型 */ @around ( "execution(* com.zkn.learnspringboot.web.controller..*.testaround*(..))" ) public object doaroundadvice(proceedingjoinpoint proceedingjoinpoint){ system.out.println( "環(huán)繞通知的目標(biāo)方法名:" +proceedingjoinpoint.getsignature().getname()); try { object obj = proceedingjoinpoint.proceed(); return obj; } catch (throwable throwable) { throwable.printstacktrace(); } return null ; } |
controller對應(yīng)的請求處理類如下:
1
2
3
4
5
|
@requestmapping ( "/testaroundservice.do" ) public string testaroundservice(string key){ return "環(huán)繞通知:" +key; } |
當(dāng)發(fā)送請求為:http://localhost:8001/aop/testaroundservice.do?key=55553
當(dāng)發(fā)送請求為:http://localhost:8001/aop/testafter02.do?key=55553&value=855sss時(shí),不符合環(huán)繞通知的切入規(guī)則,所以環(huán)繞通知不會(huì) 執(zhí)行。
完整的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(){ } /** * 前置通知,方法調(diào)用前被調(diào)用 * @param joinpoint */ @before ( "executeservice()" ) public void dobeforeadvice(joinpoint joinpoint){ system.out.println( "我是前置通知!!!" ); //獲取目標(biāo)方法的參數(shù)信息 object[] obj = joinpoint.getargs(); //aop代理類的信息 joinpoint.getthis(); //代理的目標(biāo)對象 joinpoint.gettarget(); //用的最多 通知的簽名 signature signature = joinpoint.getsignature(); //代理的是哪一個(gè)方法 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( "請求的參數(shù)信息為:" +str); } } /** * 后置返回通知 * 這里需要注意的是: * 如果參數(shù)中的第一個(gè)參數(shù)為joinpoint,則第二個(gè)參數(shù)為返回值的信息 * 如果參數(shù)中的第一個(gè)參數(shù)不為joinpoint,則第一個(gè)參數(shù)為returning中對應(yīng)的參數(shù) * returning 限定了只有目標(biāo)方法返回值與通知方法相應(yīng)參數(shù)類型時(shí)才能執(zhí)行后置返回通知,否則不執(zhí)行,對于returning對應(yīng)的通知方法參數(shù)為object類型將匹配任何目標(biāo)返回值 * @param joinpoint * @param keys */ @afterreturning (value = "execution(* com.zkn.learnspringboot.web.controller..*.*(..))" ,returning = "keys" ) public void doafterreturningadvice1(joinpoint joinpoint,object keys){ system.out.println( "第一個(gè)后置返回通知的返回值:" +keys); } @afterreturning (value = "execution(* com.zkn.learnspringboot.web.controller..*.*(..))" ,returning = "keys" ,argnames = "keys" ) public void doafterreturningadvice2(string keys){ system.out.println( "第二個(gè)后置返回通知的返回值:" +keys); } /** * 后置異常通知 * 定義一個(gè)名字,該名字用于匹配通知實(shí)現(xiàn)方法的一個(gè)參數(shù)名,當(dāng)目標(biāo)方法拋出異常返回后,將把目標(biāo)方法拋出的異常傳給通知方法; * throwing 限定了只有目標(biāo)方法拋出的異常與通知方法相應(yīng)參數(shù)異常類型時(shí)才能執(zhí)行后置異常通知,否則不執(zhí)行, * 對于throwing對應(yīng)的通知方法參數(shù)為throwable類型將匹配任何異常。 * @param joinpoint * @param exception */ @afterthrowing (value = "executeservice()" ,throwing = "exception" ) public void doafterthrowingadvice(joinpoint joinpoint,throwable exception){ //目標(biāo)方法名: system.out.println(joinpoint.getsignature().getname()); if (exception instanceof nullpointerexception){ system.out.println( "發(fā)生了空指針異常!!!!!" ); } } /** * 后置最終通知(目標(biāo)方法只要執(zhí)行完了就會(huì)執(zhí)行后置通知方法) * @param joinpoint */ @after ( "executeservice()" ) public void doafteradvice(joinpoint joinpoint){ system.out.println( "后置通知執(zhí)行了!!!!" ); } /** * 環(huán)繞通知: * 環(huán)繞通知非常強(qiáng)大,可以決定目標(biāo)方法是否執(zhí)行,什么時(shí)候執(zhí)行,執(zhí)行時(shí)是否需要替換方法參數(shù),執(zhí)行完畢是否需要替換返回值。 * 環(huán)繞通知第一個(gè)參數(shù)必須是org.aspectj.lang.proceedingjoinpoint類型 */ @around ( "execution(* com.zkn.learnspringboot.web.controller..*.testaround*(..))" ) public object doaroundadvice(proceedingjoinpoint proceedingjoinpoint){ system.out.println( "環(huán)繞通知的目標(biāo)方法名:" +proceedingjoinpoint.getsignature().getname()); try { //obj之前可以寫目標(biāo)方法執(zhí)行前的邏輯 object obj = proceedingjoinpoint.proceed(); //調(diào)用執(zhí)行目標(biāo)方法 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 "環(huán)繞通知:" +key; } } |
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:http://blog.csdn.net/zknxx/article/details/53240959