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

為什么說在SpringAOP中,不要使用This調用方法?

開發 前端
今天,我們來聊一聊,為什么說在AOP方法中,不要輕易使用This調用方法?

SpringAOP是Spring中除了依賴注入以外最為核心的功能,其原理是利用CGlib和JDK動態代理等方式來實現運行期動態方法增強,從而降低系統耦合,提升代碼的復用性。

不過,在享受AOP強大功能便利的同時,我們也會經常遇到一些看起來莫名其妙的bug。

今天,我們來聊一聊,為什么說在AOP方法中,不要輕易使用this調用方法?

使用了this會出現什么樣的情況?背后的原理是什么?又該如何解決??

廢話不多說,直接實戰上代碼。

場景復現

假設我們有一個核心支付類,其中有pay()支付功能,同時會通過record()方法記錄都有哪些用戶訪問過這個核心功能。

@Service
public class PayService {

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

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

隨著業務的不斷擴大,我們需要統計一下保存訪問日志這個動作的耗時情況,看看是否會對核心支付功能有較大的影響。

所以,我們使用SpringAOP進行了切面處理。

@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("記錄日志耗時:" + (System.currentTimeMillis() - begin));
return proceed;
}
}

切面類很簡單,通過@Around方法對record方法進行切入切出,并記錄該方法的執行時間。

?看起來很完美是不是?

老代碼不用改動,只需新增一個切面就可以實現新的需求。

我們新建一個controller,看看我們的切面類有沒有生效。

@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();
}
}

啟動服務,訪問
http://localhost:8080/demo/pay。

問題出現了。

按照上面的代碼,在打印完業務日志之后,應該打印一行記錄日志耗時的日志。然而控制臺卻空空如也,說明我們的切面類并沒有生效。

?為什么定義的切面沒有執行呢?

問題就出現在pay()方法中的this調用上。?

我們可以看到,圖中的this指向的是一個普通的PayService對象,而不是被Spring增強后的bean。

而SpringAOP起作用的原理是什么:Spring通過JDK動態代理和CGlib代理對目標類生成一個代理類,在代理類中做功能增強。

我們看一下在controller中的PayService:

可以看到,在controller中的payService是一個被SpringCLlib增強后的代理類,而我們通過this引用到的,對于Spring來說只是一個普通的bean對象,自然無法實現AOP的功能。

那Spring在什么時候會對一個對象進行代理呢?

Spring會在一個bean創建的時候判斷是否要進行代理,核心類是
AnnotationAwareAspectJAutoProxyCreator,其本質是一個BeanPostProcessor。當需要使用到AOP時,它會把創建的原始的Bean對象wrap成代理對象作為Bean返回。

所以,最終結論是:只有被動態代理出來的對象,才可以被Spring增強,具備AOP的能力。

解決辦法

既然問題找到了,那么如何解決因為this調用帶來的AOP失效的問題呢?

有兩種辦法。

一,自己引用自己

直接在當前類中注入自己,這樣Spring會對類中的屬性進行代理,生成一個payService代理類。

需要注意的是,這樣其實是人為的制造了循環依賴。在高版本的Springboot中,循環依賴是默認關閉的。如果想開啟循環依賴,需要配置
spring.main.allow-circular-references=true。

二,通過AopContext

AopContext內部維護了一個保存proxy的ThreadLocal,簡單說就是通過一個ThreadLocal將proxy和當前線程綁定起來,這樣就可以隨時拿出當前線程綁定的 Proxy。

如果使用這樣的方式,需要在@EnableAspectJAutoProxy 里加一個配置項 exposeProxy = true。

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

可以看到,成功的打印出來日志耗時的log。

總結

SpringAOP實際上會自動為我們創建一個Proxy,使得調用者能無感知地調用指定方法,本質上就是一個動態代理。我們只有訪問這些代理對象的方法,才能獲得AOP實現的功能,所以通過this引用是無法去正確使用 AOP 功能的。

責任編輯:姜華 來源: 今日頭條
相關推薦

2024-02-20 22:13:49

SQL語句編程

2014-11-21 10:50:26

JavaString

2011-03-08 12:59:38

proftpd

2017-07-03 13:33:42

AndroidItemDecorat

2012-05-24 10:29:54

編程程序員

2023-11-29 09:19:00

WebhookURL

2011-04-14 09:30:15

集合框架

2010-05-11 10:29:06

Unix awk

2014-05-19 15:52:57

Apache StraApache

2024-01-03 08:15:35

Executors線程池線程

2014-04-25 10:05:42

OpenStack私有云公共云

2024-01-24 11:24:03

C++編程異常處理

2013-09-27 11:33:57

交換機技術Vlan技術

2023-09-21 09:00:00

Merge Que開發工具Mergify

2014-01-03 10:59:34

2015-06-11 09:59:36

數據中心UPS

2023-03-06 08:01:25

structGo語言

2024-01-01 08:57:55

ODBCSqlServer數據庫

2021-12-24 17:01:29

Linux工具系統

2022-04-26 16:56:20

行為數據數據
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 高清一区二区三区 | h视频免费观看 | 一区二区三区电影在线观看 | 丝袜 亚洲 欧美 日韩 综合 | 天天曰天天曰 | 玖玖玖在线观看 | 美国一级黄色片 | 亚洲精品国产精品国自产在线 | 亚洲视频免费观看 | 午夜精品久久久久久不卡欧美一级 | 国产乱码久久久久久一区二区 | 日韩中文字幕视频在线 | 中文字幕视频在线 | 久久久久久久久91 | 精品一区电影 | 蜜桃一区二区三区在线 | 成人精品高清 | 狠狠操婷婷 | 精品区 | 九九看片| 色综合成人网 | 毛片一级片 | 高清视频一区二区三区 | 中文字幕动漫成人 | 日日操夜夜操天天操 | 九九免费视频 | 中文字幕一区在线观看视频 | 四色永久| 免费毛片www com cn | 国产一区二区在线视频 | 午夜影院 | 亚洲天堂免费 | 国产三级日本三级 | 狠狠色狠狠色综合系列 | 日本高清不卡视频 | 亚洲精品国产第一综合99久久 | 亚洲国产成人精品女人久久久 | 男女羞羞视频在线看 | 久久久久久免费看 | 9久久精品 | 国产高清亚洲 |