通過(guò)AOP環(huán)繞通知如何實(shí)現(xiàn)事務(wù)控制
通過(guò)AOP環(huán)繞通知實(shí)現(xiàn)事務(wù)控制
1、導(dǎo)入相關(guān)的依賴
<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配置方式,當(dāng)然也可以使用純注解配置
<!-- 配置數(shù)據(jù)源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!--連接數(shù)據(jù)庫(kù)的必備信息--> <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對(duì)注解AOP的支持--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
2、創(chuàng)建鏈接工具類
package com.gzl.utils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.sql.DataSource; import java.sql.Connection; /** * 連接的工具類,它用于從數(shù)據(jù)源中獲取一個(gè)連接,并且實(shí)現(xiàn)和線程的綁定 */ @Component("connectionUtils") public class ConnectionUtils { private ThreadLocal<Connection> tl = new ThreadLocal<Connection>(); @Autowired private DataSource dataSource; /** * 獲取當(dāng)前線程上的連接 * @return */ public Connection getThreadConnection() { try{ //1.先從ThreadLocal上獲取 Connection conn = tl.get(); //2.判斷當(dāng)前線程上是否有連接 if (conn == null) { //3.從數(shù)據(jù)源中獲取一個(gè)連接,并且存入ThreadLocal中 conn = dataSource.getConnection(); tl.set(conn); } //4.返回當(dāng)前線程上的連接 return conn; }catch (Exception e){ throw new RuntimeException(e); } } /** * 把連接和線程解綁 */ public void removeConnection(){ tl.remove(); } }
3、AOP環(huán)繞事務(wù)類
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; /** * 和事務(wù)管理相關(guān)的工具類,它包含了,開啟事務(wù),提交事務(wù),回滾事務(wù)和釋放連接 */ @Component("txManager") @Aspect public class TransactionManager { @Autowired private ConnectionUtils connectionUtils; /** * 需要進(jìn)行事務(wù)控制的類或者方法,EL表達(dá)式配置 */ @Pointcut("execution(* com.gzl.service.impl.*.*(..))") private void pt1(){} /** * 開啟事務(wù) */ public void beginTransaction(){ try { connectionUtils.getThreadConnection().setAutoCommit(false); }catch (Exception e){ e.printStackTrace(); } } /** * 提交事務(wù) */ public void commit(){ try { connectionUtils.getThreadConnection().commit(); }catch (Exception e){ e.printStackTrace(); } } /** * 回滾事務(wù) */ 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.獲取參數(shù) Object[] args = pjp.getArgs(); //2.開啟事務(wù) this.beginTransaction(); //3.執(zhí)行方法 rtValue = pjp.proceed(args); //4.提交事務(wù) this.commit(); //返回結(jié)果 return rtValue; }catch (Throwable e){ //5.回滾事務(wù) this.rollback(); throw new RuntimeException(e); }finally { //6.釋放資源 this.release(); } } }
spring AOP 環(huán)繞通知的思路
環(huán)繞通知Around Advice就是在指定的程序前后均執(zhí)行相關(guān)的服務(wù),設(shè)計(jì)思路如下:
1、設(shè)計(jì)一個(gè)接口
package com.spring.service; public interface IComponent { public void bussiness1(); public void bussiness2(); public void bussiness3(); }
2、編寫這個(gè)接口的實(shí)現(xiàn)
package com.spring.service; public class Component implements IComponent{ @Override public void bussiness1() { // TODO Auto-generated method stub System.out.println("這是業(yè)務(wù)1"); } @Override public void bussiness2() { // TODO Auto-generated method stub System.out.println("這是業(yè)務(wù)2"); } @Override public void bussiness3() { // TODO Auto-generated method stub System.out.println("這是業(yè)務(wù)3"); } }
3、編寫前置通知的邏輯代碼
該代碼必須實(shí)現(xiàn)org.aopalliance.intercept.Method Interceptor接口,需要的服務(wù)都寫在這里。
4、編寫XML配置文件
通過(guò)代理來(lái)實(shí)現(xiàn)AOP的環(huán)繞通知,看一下org.aopalliance.intercept.MethodInterceptor接口的源代碼。該接口不是Spring內(nèi)部的接口,而是AOP Alliance標(biāo)準(zhǔn)所指定的,不過(guò)Spring對(duì)這個(gè)接口有一個(gè)具體的實(shí)現(xiàn)過(guò)程,同時(shí)該接口相融所有遵守AOP Alliance標(biāo)準(zhǔn)的所有AOP框架。
環(huán)繞通知相當(dāng)于前置通知和后置通知的結(jié)合,不同的是在MethodInterceptor的invoke()方法中,可以自由地使用MethodInvocation提供的proceed()方法來(lái)執(zhí)行目標(biāo)對(duì)象的方法,同時(shí)proceed()方法將會(huì)返回目標(biāo)方法執(zhí)行后的返回結(jié)果,在invoke方法結(jié)束前還可以修改該結(jié)果,下面還是以上面的那個(gè)例子來(lái)示范一下環(huán)繞通知的應(yīng)用。
編寫一個(gè)環(huán)繞通知的類,該類實(shí)現(xiàn)MethodInterceptor接口。這里調(diào)用了MethodInvocation的proceed()方法,也就是說(shuō),調(diào)用了目標(biāo)對(duì)象Component中的business1等方法,在這個(gè)方法的前后分別增加了驗(yàn)證和通知執(zhí)行,接著修改一下配置文件,去掉前置通知和后置通知的配置,只需要將這個(gè)環(huán)繞通知添加進(jìn)去就可以了,具體代碼如下:
這里只需要配置一個(gè)環(huán)繞通知的Bean,并且將這個(gè)Bean配置到interceptorNames中就完成了所有的工作,測(cè)試代碼與前面的相同,可以看到結(jié)果也與前面的相同。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringCloud使用feign調(diào)用錯(cuò)誤的問題
這篇文章主要介紹了SpringCloud使用feign調(diào)用錯(cuò)誤的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06Jmeter壓力測(cè)試簡(jiǎn)單教程(包括服務(wù)器狀態(tài)監(jiān)控)
Jmeter是一個(gè)非常好用的壓力測(cè)試工具。Jmeter用來(lái)做輕量級(jí)的壓力測(cè)試,非常合適,本文詳細(xì)的介紹了Jmeter的使用,感性的可以了解一下2021-11-11easyexcel讀取excel合并單元格數(shù)據(jù)的操作代碼
這篇文章主要介紹了easyexcel讀取excel合并單元格數(shù)據(jù)的操作代碼,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-05-05linux下用renameTo方法修改java web項(xiàng)目中文件夾名稱的實(shí)例
下面小編就為大家?guī)?lái)一篇linux下用renameTo方法修改java web項(xiàng)目中文件夾名稱的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06Java 網(wǎng)絡(luò)編程之 TCP 實(shí)現(xiàn)簡(jiǎn)單的聊天系統(tǒng)
這篇文章主要介紹了Java 網(wǎng)絡(luò)編程之 TCP 實(shí)現(xiàn)簡(jiǎn)單的聊天系統(tǒng),幫助大家更好的理解和學(xué)習(xí)Java 網(wǎng)絡(luò)編程,感興趣的朋友可以了解下2020-11-11Java實(shí)現(xiàn)FTP批量大文件上傳下載篇2
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)FTP批量大文件上傳下載的強(qiáng)化篇,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-08-08SpringBoot進(jìn)行Web開發(fā)的實(shí)現(xiàn)
Spring?Boot讓我們可以快速構(gòu)建項(xiàng)目并運(yùn)行web應(yīng)用,大大簡(jiǎn)化了Spring的復(fù)雜配置,本文主要介紹了SpringBoot進(jìn)行Web開發(fā)的實(shí)現(xiàn),感興趣的可以了解一下2023-10-10深入講解spring boot中servlet的啟動(dòng)過(guò)程與原理
這篇文章主要給大家介紹了關(guān)于spring boot中servlet啟動(dòng)過(guò)程與原理的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-07-07JDBC中PreparedStatement詳解以及應(yīng)用場(chǎng)景實(shí)例介紹
PreparedStatement對(duì)象代表的是一個(gè)預(yù)編譯的SQL語(yǔ)句,用它提供的setter方法可以傳入查詢的變量,這篇文章主要給大家介紹了關(guān)于JDBC中PreparedStatement詳解以及應(yīng)用場(chǎng)景實(shí)例介紹的相關(guān)資料,需要的朋友可以參考下2024-02-02