解決spring AOP中自身方法調(diào)用無(wú)法應(yīng)用代理的問(wèn)題
spring AOP中自身方法調(diào)用無(wú)法應(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ù)無(wú)法生效,原因是spring的AOP是通過(guò)代理實(shí)現(xiàn)的,像這樣直接調(diào)用本對(duì)象的方法是不會(huì)應(yīng)用代理的。
可以使用如下兩種方式修改代碼以應(yīng)用事務(wù)
(1)在MyServiceImpl中聲明一個(gè)MyService對(duì)象
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是不會(huì)有這種自身調(diào)用的問(wèn)題的,因?yàn)樗皇腔诖淼腁OP框架。
spring aop 內(nèi)部方法調(diào)用事務(wù)不生效
方法1:
基于 proxy 的 spring aop 帶來(lái)的內(nèi)部調(diào)用問(wèn)題可以使用 AopContext.currentProxy() 強(qiáng)轉(zhuǎn)為當(dāng)前的再調(diào)用就可以解決了
例如:
錯(cuò)誤用法:
public Account getAccountByName2(String userName) {
return this.getAccountByName(userName);
}
修改為:
public Account getAccountByName2(String userName) {
return ((AccountService)AopContext.currentProxy()).getAccountByName(userName);
}
另外注意:要設(shè)置aop實(shí)體暴露出來(lái)。在springboot的application.java里面加上
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
方法2:
利用初始化方法在目標(biāo)對(duì)象中注入代理對(duì)象
在目標(biāo)對(duì)象類中注入spring上下文,通過(guò)context獲取代理對(duì)象,并調(diào)用代理對(duì)象的方法。
注意:該方案對(duì)于scope為prototype的bean無(wú)法適用,因?yàn)槊看潍@取bean時(shí)都返回一個(gè)新的對(duì)象。
方法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注入完成后會(huì)執(zhí)行該方法
private void setSelf() {
// 從spring上下文獲取代理對(duì)象(直接通過(guò)proxyObject=this是不對(duì)的,this是目標(biāo)對(duì)象)
// 此種方法不適合于prototype Bean,因?yàn)槊看蝕etBean返回一個(gè)新的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,通過(guò)注入的代理對(duì)象,調(diào)用代理對(duì)象的方法,解決內(nèi)部調(diào)用實(shí)現(xiàn)的問(wèn)題。");
proxyObject.methodB(); //調(diào)用代理對(duì)象的方法,解決內(nèi)部調(diào)用失效的問(wèn)題
}
public void methodB() {
System.out.println("method B run");
}
}
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot開(kāi)發(fā)技巧之使用AOP記錄日志示例解析
這篇文章主要為大家介紹了SpringBoot開(kāi)發(fā)技巧之如何利用AOP記錄日志的示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-10-10
Java數(shù)據(jù)結(jié)構(gòu)之散列表詳解
散列表(Hash table,也叫哈希表),是根據(jù)關(guān)鍵碼值(Key value)而直接進(jìn)行訪問(wèn)的數(shù)據(jù)結(jié)構(gòu)。本文將為大家具體介紹一下散列表的原理及其代碼實(shí)現(xiàn)2022-01-01
Spring MVC Controller返回值及異常的統(tǒng)一處理方法
這篇文章主要給大家介紹了關(guān)于Spring MVC Controller返回值及異常的統(tǒng)一處理方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用Spring MVC具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11
Mybatis動(dòng)態(tài)sql超詳細(xì)講解
動(dòng)態(tài)SQL是MyBatis的強(qiáng)大特性之一,顧名思義就是會(huì)動(dòng)的SQL,即是能夠靈活的根據(jù)某種條件拼接出完整的SQL語(yǔ)句,下面這篇文章主要給大家介紹了關(guān)于Mybatis動(dòng)態(tài)sql的相關(guān)資料,需要的朋友可以參考下2023-04-04
SpringBoot內(nèi)置tomcat啟動(dòng)原理詳解
這篇文章主要介紹了SpringBoot內(nèi)置tomcat啟動(dòng)原理詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
Java實(shí)現(xiàn)一個(gè)小說(shuō)采集程序的簡(jiǎn)單實(shí)例
下面小編就為大家?guī)?lái)一篇Java實(shí)現(xiàn)一個(gè)小說(shuō)采集程序的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的, 現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-06-06
SpringBoot 集成 Kettle的實(shí)現(xiàn)示例
本文主要介紹了SpringBoot 集成 Kettle的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-01-01
SpringBoot+Vue中的Token續(xù)簽機(jī)制
本文主要介紹了SpringBoot+Vue中的Token續(xù)簽機(jī)制,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-06-06

