解決spring AOP中自身方法調(diào)用無法應(yīng)用代理的問題
spring AOP中自身方法調(diào)用無法應(yīng)用代理
如下例
public class MyServiceImpl implements MyService { public void do(){ //the transaction annotation won't work if you directly invoke handle() method with 'this' this.handle(); } @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class) public void handle() { //sth with transaction } }
如果直接調(diào)用this的handle()方法則事務(wù)無法生效,原因是spring的AOP是通過代理實現(xiàn)的,像這樣直接調(diào)用本對象的方法是不會應(yīng)用代理的。
可以使用如下兩種方式修改代碼以應(yīng)用事務(wù)
(1)在MyServiceImpl中聲明一個MyService對象
public class MyServiceImpl implements MyService { @Autowired private MyService myService; public void do(){ //use myService object myService.handle(); } @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class) public void handle() { //sth. with transaction } }
(2)使用AopContext類
public class MyServiceImpl implements MyService { public void do(){ //fetch current proxy objet from AopContext ((MyService)AopContext.currentProxy()).handle(); } @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class) public void handle() { //sth with transaction } }
注意,原生的AspectJ是不會有這種自身調(diào)用的問題的,因為它不是基于代理的AOP框架。
spring aop 內(nèi)部方法調(diào)用事務(wù)不生效
方法1:
基于 proxy 的 spring aop 帶來的內(nèi)部調(diào)用問題可以使用 AopContext.currentProxy() 強轉(zhuǎn)為當(dāng)前的再調(diào)用就可以解決了
例如:
錯誤用法:
public Account getAccountByName2(String userName) { return this.getAccountByName(userName); }
修改為:
public Account getAccountByName2(String userName) { return ((AccountService)AopContext.currentProxy()).getAccountByName(userName); }
另外注意:要設(shè)置aop實體暴露出來。在springboot的application.java里面加上
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
方法2:
利用初始化方法在目標(biāo)對象中注入代理對象
在目標(biāo)對象類中注入spring上下文,通過context獲取代理對象,并調(diào)用代理對象的方法。
注意:該方案對于scope為prototype的bean無法適用,因為每次獲取bean時都返回一個新的對象。
方法2.1:
//延遲加載方式 private TestService testService; @Autowired @Lazy public void setTestService(TestService testService) { this.testService = testService; }
方法2.2:
import javax.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Service; import com.blog.common.aop.service.TestService; @Service public class TestServiceImpl implements TestService { @Autowired private ApplicationContext context; private TestService proxyObject; @PostConstruct // 初始化方法,在IOC注入完成后會執(zhí)行該方法 private void setSelf() { // 從spring上下文獲取代理對象(直接通過proxyObject=this是不對的,this是目標(biāo)對象) // 此種方法不適合于prototype Bean,因為每次getBean返回一個新的Bean proxyObject = context.getBean(TestService.class); } public void methodA() throws Exception { System.out.println("method A run"); System.out.println("method A 中調(diào)用method B,通過注入的代理對象,調(diào)用代理對象的方法,解決內(nèi)部調(diào)用實現(xiàn)的問題。"); proxyObject.methodB(); //調(diào)用代理對象的方法,解決內(nèi)部調(diào)用失效的問題 } public void methodB() { System.out.println("method B run"); } }
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
基于controller使用map接收參數(shù)的注意事項
這篇文章主要介紹了基于controller使用map接收參數(shù)的注意事項,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10詳解javaweb中jstl如何循環(huán)List中的Map數(shù)據(jù)
這篇文章主要介紹了詳解javaweb中jstl如何循環(huán)List中的Map數(shù)據(jù)的相關(guān)資料,希望通過本文能幫助到大家,讓大家理解掌握這部分內(nèi)容,需要的朋友可以參考下2017-10-10Java自定義過濾器和攔截器實現(xiàn)ThreadLocal線程封閉
本文主要介紹了Java自定義過濾器和攔截器實現(xiàn)ThreadLocal線程封閉,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08Java中字符串String的+和+=及循環(huán)操作String原理詳解
Java編譯器在編譯時對String的+和+=操作會創(chuàng)建StringBuilder對象來進(jìn)行字符串的拼接,下面這篇文章主要給大家介紹了關(guān)于Java中字符串String的+和+=及循環(huán)操作String原理的相關(guān)資料,需要的朋友可以參考下2023-01-01Java實現(xiàn)字節(jié)數(shù)B轉(zhuǎn)化為KB、MB、GB的方法示例【測試可用】
這篇文章主要介紹了Java實現(xiàn)字節(jié)數(shù)B轉(zhuǎn)化為KB、MB、GB的方法,結(jié)合實例形式分析了java字節(jié)數(shù)的轉(zhuǎn)換運算相關(guān)操作技巧,需要的朋友可以參考下2017-08-08