成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

為什么說(shuō)在SpringAOP中,不要使用This調(diào)用方法?

開(kāi)發(fā) 前端
今天,我們來(lái)聊一聊,為什么說(shuō)在AOP方法中,不要輕易使用This調(diào)用方法?

SpringAOP是Spring中除了依賴注入以外最為核心的功能,其原理是利用CGlib和JDK動(dòng)態(tài)代理等方式來(lái)實(shí)現(xiàn)運(yùn)行期動(dòng)態(tài)方法增強(qiáng),從而降低系統(tǒng)耦合,提升代碼的復(fù)用性。

不過(guò),在享受AOP強(qiáng)大功能便利的同時(shí),我們也會(huì)經(jīng)常遇到一些看起來(lái)莫名其妙的bug。

今天,我們來(lái)聊一聊,為什么說(shuō)在AOP方法中,不要輕易使用this調(diào)用方法?

使用了this會(huì)出現(xiàn)什么樣的情況?背后的原理是什么?又該如何解決??

廢話不多說(shuō),直接實(shí)戰(zhàn)上代碼。

場(chǎng)景復(fù)現(xiàn)

假設(shè)我們有一個(gè)核心支付類,其中有pay()支付功能,同時(shí)會(huì)通過(guò)record()方法記錄都有哪些用戶訪問(wèn)過(guò)這個(gè)核心功能。

@Service
public class PayService {

public void pay(){
System.out.println("執(zhí)行一些核心支付業(yè)務(wù)操作");
//記錄用戶訪問(wèn)日志
this.record();
}

public void record(){
try {
System.out.println("模擬將操作記錄投遞到日志系統(tǒng),耗時(shí)100ms");
TimeUnit.MICROSECONDS.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}

隨著業(yè)務(wù)的不斷擴(kuò)大,我們需要統(tǒng)計(jì)一下保存訪問(wèn)日志這個(gè)動(dòng)作的耗時(shí)情況,看看是否會(huì)對(duì)核心支付功能有較大的影響。

所以,我們使用SpringAOP進(jìn)行了切面處理。

@Aspect
@Component
public class LogAspect {

@Around(value = "execution(* com.shishan.demo2023.service.PayService.record()) )")
public Object record(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
long begin = System.currentTimeMillis();
Object proceed = proceedingJoinPoint.proceed();
System.out.println("記錄日志耗時(shí):" + (System.currentTimeMillis() - begin));
return proceed;
}
}

切面類很簡(jiǎn)單,通過(guò)@Around方法對(duì)record方法進(jìn)行切入切出,并記錄該方法的執(zhí)行時(shí)間。

?看起來(lái)很完美是不是?

老代碼不用改動(dòng),只需新增一個(gè)切面就可以實(shí)現(xiàn)新的需求。

我們新建一個(gè)controller,看看我們的切面類有沒(méi)有生效。

@RestController
@RequestMapping(value = "/demo")
public class DemoController {

@Resource
private PayService payService;

@RequestMapping(value = "/pay")
public ResponseEntity<Object> pay(){
this.payService.pay();
return ResponseEntity.ok().build();
}
}

啟動(dòng)服務(wù),訪問(wèn)
http://localhost:8080/demo/pay。

問(wèn)題出現(xiàn)了。

按照上面的代碼,在打印完業(yè)務(wù)日志之后,應(yīng)該打印一行記錄日志耗時(shí)的日志。然而控制臺(tái)卻空空如也,說(shuō)明我們的切面類并沒(méi)有生效。

?為什么定義的切面沒(méi)有執(zhí)行呢?

問(wèn)題就出現(xiàn)在pay()方法中的this調(diào)用上。?

我們可以看到,圖中的this指向的是一個(gè)普通的PayService對(duì)象,而不是被Spring增強(qiáng)后的bean。

而SpringAOP起作用的原理是什么:Spring通過(guò)JDK動(dòng)態(tài)代理和CGlib代理對(duì)目標(biāo)類生成一個(gè)代理類,在代理類中做功能增強(qiáng)。

我們看一下在controller中的PayService:

可以看到,在controller中的payService是一個(gè)被SpringCLlib增強(qiáng)后的代理類,而我們通過(guò)this引用到的,對(duì)于Spring來(lái)說(shuō)只是一個(gè)普通的bean對(duì)象,自然無(wú)法實(shí)現(xiàn)AOP的功能。

那Spring在什么時(shí)候會(huì)對(duì)一個(gè)對(duì)象進(jìn)行代理呢?

Spring會(huì)在一個(gè)bean創(chuàng)建的時(shí)候判斷是否要進(jìn)行代理,核心類是
AnnotationAwareAspectJAutoProxyCreator,其本質(zhì)是一個(gè)BeanPostProcessor。當(dāng)需要使用到AOP時(shí),它會(huì)把創(chuàng)建的原始的Bean對(duì)象wrap成代理對(duì)象作為Bean返回。

所以,最終結(jié)論是:只有被動(dòng)態(tài)代理出來(lái)的對(duì)象,才可以被Spring增強(qiáng),具備AOP的能力。

解決辦法

既然問(wèn)題找到了,那么如何解決因?yàn)閠his調(diào)用帶來(lái)的AOP失效的問(wèn)題呢?

有兩種辦法。

一,自己引用自己

直接在當(dāng)前類中注入自己,這樣Spring會(huì)對(duì)類中的屬性進(jìn)行代理,生成一個(gè)payService代理類。

需要注意的是,這樣其實(shí)是人為的制造了循環(huán)依賴。在高版本的Springboot中,循環(huán)依賴是默認(rèn)關(guān)閉的。如果想開(kāi)啟循環(huán)依賴,需要配置
spring.main.allow-circular-references=true。

二,通過(guò)AopContext

AopContext內(nèi)部維護(hù)了一個(gè)保存proxy的ThreadLocal,簡(jiǎn)單說(shuō)就是通過(guò)一個(gè)ThreadLocal將proxy和當(dāng)前線程綁定起來(lái),這樣就可以隨時(shí)拿出當(dāng)前線程綁定的 Proxy。

如果使用這樣的方式,需要在@EnableAspectJAutoProxy 里加一個(gè)配置項(xiàng) exposeProxy = true。

通過(guò)方式一修改下代碼,看看AOP是否生效。

可以看到,成功的打印出來(lái)日志耗時(shí)的log。

總結(jié)

SpringAOP實(shí)際上會(huì)自動(dòng)為我們創(chuàng)建一個(gè)Proxy,使得調(diào)用者能無(wú)感知地調(diào)用指定方法,本質(zhì)上就是一個(gè)動(dòng)態(tài)代理。我們只有訪問(wèn)這些代理對(duì)象的方法,才能獲得AOP實(shí)現(xiàn)的功能,所以通過(guò)this引用是無(wú)法去正確使用 AOP 功能的。

責(zé)任編輯:姜華 來(lái)源: 今日頭條
相關(guān)推薦

2024-02-20 22:13:49

SQL語(yǔ)句編程

2017-07-03 13:33:42

AndroidItemDecorat

2014-11-21 10:50:26

JavaString

2011-03-08 12:59:38

proftpd

2012-05-24 10:29:54

編程程序員

2023-11-29 09:19:00

WebhookURL

2010-05-11 10:29:06

Unix awk

2014-05-19 15:52:57

Apache StraApache

2011-04-14 09:30:15

集合框架

2024-01-03 08:15:35

Executors線程池線程

2013-09-27 11:33:57

交換機(jī)技術(shù)Vlan技術(shù)

2014-04-25 10:05:42

OpenStack私有云公共云

2024-01-24 11:24:03

C++編程異常處理

2023-09-21 09:00:00

Merge Que開(kāi)發(fā)工具Mergify

2014-01-03 10:59:34

2023-03-06 08:01:25

structGo語(yǔ)言

2024-01-01 08:57:55

ODBCSqlServer數(shù)據(jù)庫(kù)

2021-12-24 17:01:29

Linux工具系統(tǒng)

2015-06-11 09:59:36

數(shù)據(jù)中心UPS

2018-01-08 08:28:44

Linux命令
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 国产激情精品视频 | 欧美午夜精品久久久久免费视 | 精品视频一区二区三区在线观看 | 祝你幸福电影在线观看 | 国产精品爱久久久久久久 | 人人人人干 | 亚洲高清网 | 在线视频91 | 91九色视频 | 中文字幕在线观看国产 | 自拍视频国产 | 成人欧美 | 久久1区| 日本精品久久久久久久 | 亚洲精品成人在线 | 日韩精品色网 | 久久天堂网| 91麻豆产精品久久久久久夏晴子 | 成人国产精品久久久 | 日韩伦理一区二区三区 | 成人激情视频免费观看 | www.中文字幕.com | 成人免费三级电影 | 欧美亚洲激情 | 国产在线观看 | 久久久久国产一区二区三区四区 | 国产免费一区二区 | 狠狠爱视频 | 国产高清精品在线 | 色综合色综合色综合 | 91高清在线视频 | 亚洲一区免费在线 | 午夜欧美 | 日本特黄a级高清免费大片 国产精品久久性 | 精品在线 | 日韩av一区二区在线 | 一区中文字幕 | 男人的天堂avav | 欧美日韩久久 | 91偷拍精品一区二区三区 | 一级毛片视频 |