通過AOP環繞通知實現事務控制
1、導入相關的依賴
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
< dependencies > < dependency > < groupId >org.springframework</ groupId > < artifactId >spring-context</ artifactId > < version >5.0.2.RELEASE</ version > </ dependency > < dependency > < groupId >c3p0</ groupId > < artifactId >c3p0</ artifactId > < version >0.9.1.2</ version > </ dependency > < dependency > < groupId >org.aspectj</ groupId > < artifactId >aspectjweaver</ artifactId > < version >1.8.7</ version > </ dependency > </ dependencies > |
2、配置連接池和開啟AOP注解
以下采用的是xml配置方式,當然也可以使用純注解配置
1
2
3
4
5
6
7
8
9
10
|
<!-- 配置數據源 --> < bean id = "dataSource" class = "com.mchange.v2.c3p0.ComboPooledDataSource" > <!--連接數據庫的必備信息--> < property name = "driverClass" value = "com.mysql.jdbc.Driver" ></ property > < property name = "jdbcUrl" value = "jdbc:mysql://localhost:3306/test" ></ property > < property name = "user" value = "root" ></ property > < property name = "password" value = "root" ></ property > </ bean > <!--開啟spring對注解AOP的支持--> < aop:aspectj-autoproxy ></ aop:aspectj-autoproxy > |
2、創建鏈接工具類
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
|
package com.gzl.utils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.sql.DataSource; import java.sql.Connection; /** * 連接的工具類,它用于從數據源中獲取一個連接,并且實現和線程的綁定 */ @Component ( "connectionUtils" ) public class ConnectionUtils { private ThreadLocal<Connection> tl = new ThreadLocal<Connection>(); @Autowired private DataSource dataSource; /** * 獲取當前線程上的連接 * @return */ public Connection getThreadConnection() { try { //1.先從ThreadLocal上獲取 Connection conn = tl.get(); //2.判斷當前線程上是否有連接 if (conn == null ) { //3.從數據源中獲取一個連接,并且存入ThreadLocal中 conn = dataSource.getConnection(); tl.set(conn); } //4.返回當前線程上的連接 return conn; } catch (Exception e){ throw new RuntimeException(e); } } /** * 把連接和線程解綁 */ public void removeConnection(){ tl.remove(); } } |
3、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
|
package com.gzl.utils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * 和事務管理相關的工具類,它包含了,開啟事務,提交事務,回滾事務和釋放連接 */ @Component ( "txManager" ) @Aspect public class TransactionManager { @Autowired private ConnectionUtils connectionUtils; /** * 需要進行事務控制的類或者方法,EL表達式配置 */ @Pointcut ( "execution(* com.gzl.service.impl.*.*(..))" ) private void pt1(){} /** * 開啟事務 */ public void beginTransaction(){ try { connectionUtils.getThreadConnection().setAutoCommit( false ); } catch (Exception e){ e.printStackTrace(); } } /** * 提交事務 */ public void commit(){ try { connectionUtils.getThreadConnection().commit(); } catch (Exception e){ e.printStackTrace(); } } /** * 回滾事務 */ public void rollback(){ try { connectionUtils.getThreadConnection().rollback(); } catch (Exception e){ e.printStackTrace(); } } /** * 釋放連接 */ public void release(){ try { connectionUtils.getThreadConnection().close(); //還回連接池中 connectionUtils.removeConnection(); } catch (Exception e){ e.printStackTrace(); } } @Around ( "pt1()" ) public Object aroundAdvice(ProceedingJoinPoint pjp){ Object rtValue = null ; try { //1.獲取參數 Object[] args = pjp.getArgs(); //2.開啟事務 this .beginTransaction(); //3.執行方法 rtValue = pjp.proceed(args); //4.提交事務 this .commit(); //返回結果 return rtValue; } catch (Throwable e){ //5.回滾事務 this .rollback(); throw new RuntimeException(e); } finally { //6.釋放資源 this .release(); } } } |
spring AOP 環繞通知的思路
環繞通知Around Advice就是在指定的程序前后均執行相關的服務,設計思路如下:
1、設計一個接口
1
2
3
4
5
6
|
package com.spring.service; public interface IComponent { public void bussiness1(); public void bussiness2(); public void bussiness3(); } |
2、編寫這個接口的實現
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package com.spring.service; public class Component implements IComponent{ @Override public void bussiness1() { // TODO Auto-generated method stub System.out.println( "這是業務1" ); } @Override public void bussiness2() { // TODO Auto-generated method stub System.out.println( "這是業務2" ); } @Override public void bussiness3() { // TODO Auto-generated method stub System.out.println( "這是業務3" ); } } |
3、編寫前置通知的邏輯代碼
該代碼必須實現org.aopalliance.intercept.Method Interceptor接口,需要的服務都寫在這里。
4、編寫XML配置文件
通過代理來實現AOP的環繞通知,看一下org.aopalliance.intercept.MethodInterceptor接口的源代碼。該接口不是Spring內部的接口,而是AOP Alliance標準所指定的,不過Spring對這個接口有一個具體的實現過程,同時該接口相融所有遵守AOP Alliance標準的所有AOP框架。
環繞通知相當于前置通知和后置通知的結合,不同的是在MethodInterceptor的invoke()方法中,可以自由地使用MethodInvocation提供的proceed()方法來執行目標對象的方法,同時proceed()方法將會返回目標方法執行后的返回結果,在invoke方法結束前還可以修改該結果,下面還是以上面的那個例子來示范一下環繞通知的應用。
編寫一個環繞通知的類,該類實現MethodInterceptor接口。這里調用了MethodInvocation的proceed()方法,也就是說,調用了目標對象Component中的business1等方法,在這個方法的前后分別增加了驗證和通知執行,接著修改一下配置文件,去掉前置通知和后置通知的配置,只需要將這個環繞通知添加進去就可以了,具體代碼如下:
這里只需要配置一個環繞通知的Bean,并且將這個Bean配置到interceptorNames中就完成了所有的工作,測試代碼與前面的相同,可以看到結果也與前面的相同。
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/weixin_43888891/article/details/109323679