「本文已參與好文召集令活動,點擊查看:後端、大前端雙賽道投稿,2萬元獎池等你挑戰!」前端
Springboot
中 AOP
失效的緣由今天 4ye 來和小夥伴們分享一個小實戰啦 ,沖沖衝~ (。・∀・)ノjava
(我竟然拖到如今才寫了這文章…… 😵)git
主要是在一個週日(2020.6.6)在技術羣裏看到一個老哥在問github
「怎麼用切面來捕獲自定義異常?」 ( ̄▽ ̄)"web
我當時想的是,捕獲異常不是很常見的嗎,平時常常用到這個全局異常捕獲 ,因而就把本身 GitHub
上的小例子發給他(主要是這個 ControllerAdvice
註解),如圖 👇spring
結果老哥過了一段時候就加了我,還問我有沒有空幫忙看下,還想打電話問我,我當時的心裏是後端
這麼急的嗎(瑟瑟發抖……)springboot
不過恰好在外面沒時間,就婉拒了,後來晚上回來,愣是花了兩個鍾,纔看懂 爲啥這個AOP
沒有生效?爲啥沒能捕獲到異常?markdown
下面進入主題👉(項目總體介紹)maven
在該項目中,maven項目採用多模塊構建,父子結構,由 父maven 來統一管理這些公共包,以及項目的總體版本屬性配置等
裏面有兩個模塊,starter
模塊和 core
模塊,其中 starter
模塊依賴 core
模塊,總體以下圖👇
不知道小夥伴們看到上面的 starter
有沒有嗅到什麼 ?
一開始我覺得是常見的 自定義starter ,可是裏面的內容卻和我想的有點出入,竟然只有一個 spring.factories
文件, 很明顯這裏使用到了 Springboot 的 SPI 機制。
這個在咱們以前的 👉 Springboot自動裝配原理探索 一文中有介紹到,小夥伴們能夠前去了解看看~😄
對兩個模塊中的核心部分進行展開,結構以下👇
core項目描述:非web項目裏面只有 service
,沒有啓動類等
👉 因爲 core 模塊 不是web項目!!,因此這個 ControllerAdvice
是確定不能用的,畢竟它是在 web
包中的,通常咱們在 web項目中配合這個@ExceptionHandler(Exception.class)
實現全局異常捕獲,而後進行統一處理的。
👉 從 Springboot 的 SPI 機制 中咱們能夠得知,Springboot
項目啓動時,會去掃描各個項目中的 META-INF/spring.factories
文件(包括各個jar包),而後將其中的配置信息讀取到內存中,而自動配置時會根據必定的條件對這些類進行篩選,最後建立符合的類,完成這個自動裝配。
很明顯,這裏就是經過自動配置,來實現相關 bean
的注入。
那麼,在瞭解了這些基本信息後,咱們能夠把目光移到這個 xxxConfig
上,這裏模仿了一個👇
緊接着就是項目中的切面配置了,例如之前寫的小例子:👇
代碼在個人 GitHub
:
經過異常通知來捕獲
除了上面這兩個以外,項目中沒有用到其餘配置了!
這個時候問題就來了,在定義了切面以後,發現根本沒有在項目中起做用!而其餘均可以正常運行!
因而我一直在想,這是爲啥呀,明明切面已經定義好了呀……
終於,我開始了嘗試,在 yaml
配置文件中添加這個參數
spring:
aop:
auto: true
複製代碼
由於在印象中,這個默認是 true
,會默認使用這個 @EnableAspectJAutoProxy
, 不用咱們手動去添加這個 @EnableAspectJAutoProxy
註解(以前一直沒有手動添加這個註解)🐖
結果也沒什麼效果……
因而乎,我決定手動添加到剛剛那個 xxxConfig
配置類上,結果也沒有什麼做用……
終於,我纔想起那個 切面配置 沒有被加載到這個 Spring
中 ,因而我又在那個配置類 xxxConfig
上添加了這個包掃描註解 @ComponentScan(basePackages = "com.xxx.xxx")
結果終於成功了!
因而我趕在 23:59 將修改後的文件發給那位老哥後,卻發現他竟然睡着了 哈哈哈
解決問題後,咱們能夠發現這個問題就下面兩點👇
SpringIOC
容器中@EnableAspectJAutoProxy
第一步的解決也很簡單,就是沒有配置這個包掃描 @ComponentScan(basePackages = "com.xxx.xxx")
第二步的解決嘛,就有點一頭霧水了當時,畢竟以前也不須要我手動去添加的,並且從配置的描述信息中能夠發現,即便咱們沒有配置,他也是默認開啓的,會自動使用這個註解的~
那麼小夥伴們知道第二步問題的所在嗎😄
嘿嘿,答案就出在這個自動配置 身上,能夠發現咱們上面都沒有使用到這個 @EnableAutoConfiguration
註解,而在咱們的 SpringBootApplication
組合註解中,最重要的就是它了! 經過它去開啓了咱們的這個自動裝配。
這個時候又得把這文章搬出來了 👉 Springboot自動裝配原理探索 哈哈
那麼咱們再來看看這個 AOP自動裝配的配置類
AopAutoConfiguration
源碼以下👇
開頭有這麼一個條件註解
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
複製代碼
havingValue = "true"
的意思是:值爲 true
時纔有效
matchIfMissing = true
的意思是:沒有配置這個屬性時也能加載
接着讓咱們把目光移到第一個靜態內部類: AspectJAutoProxyingConfiguration
如圖👉:
這個咱們也比較熟悉啦, proxyTargetClass
爲 true
時表示使用 cglib
,false
使用 JDK
動態代理
接着看最後的靜態內部類: ClassProxyingConfiguration
能夠發現它這裏的條件是和 AspectJAutoProxyingConfiguration
相反的,當沒有這個 Advice
類時,幫咱們去註冊這個代理到 IOC
中
看完該AOP自動裝配類後, 咱們能夠發現當咱們使用 @EnableAutoConfiguration
自動裝配註解時並引入 AOP
的包時,它會自動幫咱們裝配這個AopAutoConfiguration
,而它裏面就使用到了 @EnableAspectJAutoProxy
,因此咱們通常不用手動添加該註解。
嘿嘿,再出一個小問題考考小夥伴😝
有沒有細心的小夥伴發現上面的 core
模塊是沒有用到這個 SpringBootApplication
的,並且咱們也沒有用到這個 @EnableAutoConfiguration
,那麼沒有自動裝配,這個 SPI
顯然也沒啥做用 ,那麼,咱們在項目中要怎麼測試呢~
答案就在 單元測試的註解身上 @SpringBootTest(classes = xxxConfiguration.class)
經過這個 classes
,咱們直接指定並實例化這個配置類就能夠了
我也是報錯了才知道 哈哈😝
嘿嘿,老規矩,畫個圖總結下啦👇
那麼,本期就分享到這啦,喜歡的小夥伴記得點點贊呀~ 下期看看狀況分享下下面某一個叭😝
歡迎小夥伴們來一塊兒探討問題~
若是你以爲本篇文章還不錯的話,那拜託再點點贊支持一下呀😝
讓咱們開始這一場意外的相遇吧!~
歡迎留言!謝謝支持!ヾ(≧▽≦*)o 沖沖衝!!
我是4ye 我們下期應該……很快再見!! 😆