這篇文章給大家介紹了springAOP的實現(xiàn)方式,三種分別是純XML方式,XML+注解,純注解方式。
Spring 實現(xiàn)AOP思想使?的是動態(tài)代理技術(shù)
默認(rèn)情況下, Spring會根據(jù)被代理對象是否實現(xiàn)接?來選擇使?JDK還是CGLIB。當(dāng)被代理對象沒有實現(xiàn)
任何接?時, Spring會選擇CGLIB。當(dāng)被代理對象實現(xiàn)了接?, Spring會選擇JDK官?的代理技術(shù),不過
我們可以通過配置的?式,讓Spring強制使?CGLIB。
接下來我們開始實現(xiàn)aop,
需求是:橫切邏輯代碼是打印?志,希望把打印?志的邏輯織?到?標(biāo)?法的特定位置(service層transfer?法)
純XML方式
引入aop相關(guān)的jar包
1
2
3
4
5
6
7
8
9
10
11
|
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version> 5.1 . 12 .RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version> 1.9 . 4 </version> </dependency> |
TransferServiceImpl.java文件:
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.lagou.edu.service.impl; import com.lagou.edu.dao.AccountDao; import com.lagou.edu.pojo.Account; import com.lagou.edu.service.TransferService; import com.lagou.edu.utils.ConnectionUtils; import com.lagou.edu.utils.TransactionManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.ImportResource; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; /** * @author 應(yīng)癲 */ @Service ( "transferService" ) public class TransferServiceImpl implements TransferService { // 最佳狀態(tài) // @Autowired 按照類型注入 ,如果按照類型無法唯一鎖定對象,可以結(jié)合@Qualifier指定具體的id @Autowired @Qualifier ( "accountDao" ) private AccountDao accountDao; @Override public void transfer(String fromCardNo, String toCardNo, int money) throws Exception { /*try{ // 開啟事務(wù)(關(guān)閉事務(wù)的自動提交) TransactionManager.getInstance().beginTransaction();*/ System.out.println( "執(zhí)行轉(zhuǎn)賬業(yè)務(wù)邏輯" ); Account from = accountDao.queryAccountByCardNo(fromCardNo); Account to = accountDao.queryAccountByCardNo(toCardNo); from.setMoney(from.getMoney()-money); to.setMoney(to.getMoney()+money); accountDao.updateAccountByCardNo(to); //int c = 1/0; accountDao.updateAccountByCardNo(from); } } |
打印日志Util:
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
|
package com.lagou.edu.utils; /** * @author 應(yīng)癲 */ public class LogUtils { /** * 業(yè)務(wù)邏輯開始之前執(zhí)行 */ public void beforeMethod(JoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); for ( int i = 0 ; i < args.length; i++) { Object arg = args[i]; System.out.println(arg); } System.out.println( "業(yè)務(wù)邏輯開始執(zhí)行之前執(zhí)行......." ); } /** * 業(yè)務(wù)邏輯結(jié)束時執(zhí)行(無論異常與否) */ public void afterMethod() { System.out.println( "業(yè)務(wù)邏輯結(jié)束時執(zhí)行,無論異常與否都執(zhí)行......." ); } /** * 異常時時執(zhí)行 */ public void exceptionMethod() { System.out.println( "異常時執(zhí)行......." ); } /** * 業(yè)務(wù)邏輯正常時執(zhí)行 */ public void successMethod(Object retVal) { System.out.println( "業(yè)務(wù)邏輯正常時執(zhí)行......." ); } } public Object arroundMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println( "環(huán)繞通知中的beforemethod...." ); Object result = null ; try { // 控制原有業(yè)務(wù)邏輯是否執(zhí)行 // result = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs()); } catch (Exception e) { System.out.println( "環(huán)繞通知中的exceptionmethod...." ); } finally { System.out.println( "環(huán)繞通知中的after method...." ); } return result; } |
applicationContext.xml
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
|
<!--進(jìn)行aop相關(guān)的xml配置,配置aop的過程其實就是把aop相關(guān)術(shù)語落地--> <!--橫切邏輯bean--> <bean id= "logUtils" class = "com.lagou.edu.utils.LogUtils" ></bean> <!--使用config標(biāo)簽表明開始aop配置,在內(nèi)部配置切面aspect--> <!--aspect = 切入點(鎖定方法) + 方位點(鎖定方法中的特殊時機(jī))+ 橫切邏輯 --> <aop:config> <aop:aspect id= "logAspect" ref= "logUtils" > <!--切入點鎖定我們感興趣的方法,使用aspectj語法表達(dá)式--> <!--..參數(shù)中的兩個點表示可以有參數(shù),也可以沒有參數(shù),有的話也可以是任意類型,參數(shù)中的 *表示參數(shù)可以是任意類型,但必須有參數(shù)。 --> <!--包名中的..兩個點表示中間可以是任意層--> <!--<aop:pointcut id= "pt1" expression= "execution(* *..*.*(..))" />--> <aop:pointcut id= "pt1" expression= "execution(public void com.lagou.edu.service.impl.TransferServiceImpl.transfer(java.lang.String,java.lang.String,int))" /> <!-- <aop:pointcut id= "pt1" expression= "execution(* com.lagou.edu.service.impl.TransferServiceImpl.*(..))" /> --> <!--方位信息,pointcut-ref關(guān)聯(lián)切入點--> <!--aop:before前置通知/增強--> <aop:before method= "beforeMethod" pointcut-ref= "pt1" /> <!--aop:after,最終通知,無論如何都執(zhí)行--> <!--aop:after-returnning,正常執(zhí)行通知,retValue是接受方法的返回值的--> <aop:after-returning method= "successMethod" returning= "retValue" /> <!--aop:after-throwing,異常通知--> <aop:around method= "arroundMethod" pointcut-ref= "pt1" /> </aop:aspect> </aop:config>--> |
測試:
1
2
3
4
5
6
7
8
9
|
/** * 測試xml aop */ @Test public void testXmlAop() throws Exception { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext( "classpath:applicationContext.xml" ); TransferService transferService = applicationContext.getBean(TransferService. class ); transferService.transfer( "6029621011000" , "6029621011001" , 100 ); } |
環(huán)繞通知不和前置及后置通知一起使用,因為環(huán)繞通知可以實現(xiàn)前置和后置的功能,并且可以控制原有業(yè)務(wù)邏輯是否執(zhí)行,非常強大。
XML+注解方式
將上面純XML方式改為注解方式
將applicationContext.xml中的內(nè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
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
|
package com.lagou.edu.utils; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; /** * @author 應(yīng)癲 */ @Component @Aspect public class LogUtils { @Pointcut ( "execution(* com.lagou.edu.service.impl.TransferServiceImpl.*(..))" ) public void pt1(){ } /** * 業(yè)務(wù)邏輯開始之前執(zhí)行 */ @Before ( "pt1()" ) public void beforeMethod(JoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); for ( int i = 0 ; i < args.length; i++) { Object arg = args[i]; System.out.println(arg); } System.out.println( "業(yè)務(wù)邏輯開始執(zhí)行之前執(zhí)行......." ); } /** * 業(yè)務(wù)邏輯結(jié)束時執(zhí)行(無論異常與否) */ @After ( "pt1()" ) public void afterMethod() { System.out.println( "業(yè)務(wù)邏輯結(jié)束時執(zhí)行,無論異常與否都執(zhí)行......." ); } /** * 異常時時執(zhí)行 */ @AfterThrowing ( "pt1()" ) public void exceptionMethod() { System.out.println( "異常時執(zhí)行......." ); } /** * 業(yè)務(wù)邏輯正常時執(zhí)行 */ @AfterReturning (value = "pt1()" ,returning = "retVal" ) public void successMethod(Object retVal) { System.out.println( "業(yè)務(wù)邏輯正常時執(zhí)行......." ); } /** * 環(huán)繞通知 * */ /*@Around("pt1()")*/ public Object arroundMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println( "環(huán)繞通知中的beforemethod...." ); Object result = null ; try { // 控制原有業(yè)務(wù)邏輯是否執(zhí)行 // result = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs()); } catch (Exception e) { System.out.println( "環(huán)繞通知中的exceptionmethod...." ); } finally { System.out.println( "環(huán)繞通知中的after method...." ); } return result; } } |
在application.xml中配置注解驅(qū)動:
1
2
3
4
5
|
<!--開啟aop注解驅(qū)動 proxy-target- class : true 強制使用cglib --> <aop:aspectj-autoproxy/> |
純注解模式
我們只需要替換掉xml+注解模式中的注解驅(qū)動的部分即可,
將
1
2
3
4
5
|
<!--開啟aop注解驅(qū)動 proxy-target- class : true 強制使用cglib --> <aop:aspectj-autoproxy/> |
改為 @EnableAspectJAutoProxy
//開啟spring對注解AOP的?持,在項目中添加到任意個配置類上即可。
到此這篇關(guān)于springAOP的三種實現(xiàn)方式的文章就介紹到這了,更多相關(guān)springAOP實現(xiàn)方式內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://www.cnblogs.com/liuyj-top/p/13346206.html