亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何用最通俗的方法講spring中的AOP

發布時間:2021-10-20 17:35:50 來源:億速云 閱讀:125 作者:柒染 欄目:大數據

這篇文章給大家介紹如何用最通俗的方法講spring中的AOP,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

寫這個系列的目的(可以跳過不看)

自己寫這個系列的目的,是因為自己是個比較笨的人,我曾一度懷疑自己的智商不適合干編程這個行業.因為在我自學的過程中,看過無數別人的文章,博客,心得.可那一大堆的術語,技術基礎,根本就難以閱讀理解.再加上網上文章良莠不齊,很多文章都是寫給已經懂的人看的. 一個例子: Q:什么是控制反轉. A:將對在自身對象中的一個內置對象的控制反轉,反轉后不再由自己本身的對象進行控制這個內置對象的創建,而是由第三方系統去控制這個內置對象的創建. ??? 這種專業的解釋,在我看來就不是給學習的人看的,而是給已經有相當經驗的人讀的. 難道不能用更加感性的解釋這些東西嗎? 編程語言作為一門語言,我認為一定程度上是相當感性的東西,既然我們互相說話時可以聽懂,那么,這些技術就可以在一定程度上,完全可以用感性的方式解釋.

AOP

AOP是面向切面. 得,說了白說. 什么是面向切面?這是個問題,但我們先不著急回答.

一. 舉個例子

我們的代碼結構,大多都是MVC模式.那我們用MVC舉個簡單的例子. MVC模式的話,最常用的spring + springMVC + Mybatis,大多數是下面的樣子.

┌───────────────┐
|   view        | 用戶界面
├───────────────┤
|   Controller  | 控制層
├───────────────┤
|   Service     | 服務層,也叫業務層
├───────────────┤
|   Dao         | 持久層,也叫數據訪問層
├───────────────┤
|   Database    | 數據庫
└───────────────┘

外加Model作為數據載體在各個層之間傳來傳去 只要是接觸過JavaWeb開發的,上面都看的懂,如果這個不懂暫時還是不要深究這些知識,先以框架應用為主.

這個Service是個UserService,作用只有一個:保存用戶.

┌────────────────────┐
|   view             |
├────────────────────┤
|   Controller       |
├────────────────────┤
|   UserService.add  | ───> 新增用戶
├────────────────────┤
|   Dao              |
├────────────────────┤
|   Database         |
└────────────────────┘

現在,有需求要我們在Service中增加日志,開發這個功能的同事不在了,經理要求我們來做這個需求. 那么根據面向對象的理念. 調用service方法前要調用一個日志方法,調用完后要調用一個日志方法,那么代碼中就要增加兩行代碼. 于是,代碼成了這樣:

┌────────────────────┐
|   view             |
├────────────────────┤
|   Controller       |
├────────────────────┤
|   log.info...      | ───> 調用日志
|   UserService.add  | ───> 新增用戶
|   log.info...      | ───> 調用日志
├────────────────────┤
|   Dao              |
├────────────────────┤
|   Database         |
└────────────────────┘

這么寫正確嗎? 答案是當然正確,需求解決了,日志正常保存了,領導很高興.

第二天,又有需求要控制service的事務,OK,然后代碼變成了這樣.

┌────────────────────┐
|   view             |
├────────────────────┤
|   Controller       |
├────────────────────┤
|   Transaction      | ───> 事務管理
|   log.info...      | ───> 調用日志
|   UserService.add  | ───> 新增用戶
|   log.info...      | ───> 調用日志
|   Transaction      | ───> 事務管理
├────────────────────┤
|   Dao              |
├────────────────────┤
|   Database         |
└────────────────────┘

第三天,項目經理要求我們記錄方法的運行所用時間,小意思,然后代碼變成了這樣

┌────────────────────┐
|   view             |
├────────────────────┤
|   Controller       |
├────────────────────┤
|   beginTime        | ───> 開始時間
|   Transaction      | ───> 事務管理
|   log.info...      | ───> 調用日志
|   UserService.add  | ───> 新增用戶
|   log.info...      | ───> 調用日志
|   Transaction      | ───> 事務管理
|   endTime          | ───> 結束時間
├────────────────────┤
|   Dao              |
├────────────────────┤
|   Database         |
└────────────────────┘

第四天,客戶要求我們實現新增用戶時的權限校驗,好說,代碼變成了這樣

┌────────────────────┐
|   view             |
├────────────────────┤
|   Controller       |
├────────────────────┤
|   permissions      | ───> 校驗權限
|   beginTime        | ───> 開始時間
|   Transaction      | ───> 事務管理
|   log.info...      | ───> 調用日志
|   UserService.add  | ───> 新增用戶
|   log.info...      | ───> 調用日志
|   Transaction      | ───> 事務管理
|   endTime          | ───> 結束時間
├────────────────────┤
|   Dao              |
├────────────────────┤
|   Database         |
└────────────────────┘

/*
不知道你們怎么想,但我現在,仍然覺得這種寫法挺好的.
通俗易懂,可讀性強到不知道哪里去了.
當然有個前提,這個項目只有這一個方法.
*/

第五天,開發UserService的同事回來一看,一臉懵逼,明明走的時候只有一行,現在卻有一大堆不知道什么意思的代碼存在. 得了,他在此基礎上開發,增加各種方法,功能. 隨著需求的變動,慢慢的,一百個service都變成了上面那個樣子. 接著記錄日志的功能有了變動,你發現會影響到調用的類,搜了一下整個項目,發現有特么幾千個地方都調用了這個方法. 你心中一萬頭草泥馬掠過,然后提出了辭職. 接著有個新人接手了這個項目,打開一看,這映入眼簾的一大坨屎一樣的是特么什么東西?? 硬著頭皮改了幾版,每個版本都有BUG,領導一怒之下,項目作廢了,重金找了幾個人重新做了.

==那么問題來了== 現在的需求搞砸了可以辭職,項目爛了可以重做. 那世界上第一個遇到這個問題的人,是怎么解決的?技術就是這技術,重做不還是一樣會遇到這些問題嗎?那我還怎么拓展功能呢?難道所有項目最終都會走向這種絕境? 于是前人開始探索:

┌───────────────┐
|   Controller  |
|               ┼───────> 拓展方法寫在這?
├───────────────┤
|   Service     |
├───────────────┤
|               ┼───────> 拓展方法寫在這?
|    Dao        |
└───────────────┘

這不都是一回事嗎?根本不解決問題.

我等凡夫俗子解決不了,但世界上有的是自帶外掛的人. 于是,有那么幾個人就找到了解決辦法! 既然我要拓展方法,就要在你的方法里寫代碼,那么我能不能在不改你代碼的基礎上來拓展呢?

==比如在這個地方!==

┌───────────────┐
|   Controller  |
├───────────────┼───────> 比如,寫在這!
|   Service     |
└───────────────┘

what the hell ?????? 你是讓我在一個莫須有的地方寫代碼?

當然不是,大神的意思是代碼要這樣寫.

┌───────────────┐
|   Controller  |      ┌───────────────┐
├───────────────┼──────┤ log.info...   |
|   Service     |      └───────────────┘
└───────────────┘

但執行的時候,會是這樣

┌───────────────┐
|   Controller  |
├───────────────┤
|   log.info... |
|   Service     |
└───────────────┘

what the hell ??????????????????????????????? 這是為什么?

==答案很簡單:== 首先你既然打算了解AOP,那你應該是有一些Java基礎的. 我們都知道Java文件是沒有用的,這就相當于一個txt文件,當程序真正運行的時候,是把Java文件通過編譯器編譯成class文件來運行的. 那么我們好像看到重點了,編譯器! 既然最終運行的是class文件,而class文件又是編譯器生成的,那我們是不是可以在編譯器上動動手腳呢? 沒錯,想要達成上面的效果,就需要一個不同的編譯器. 把日志這段代碼編譯到service中 當然了,這個編譯器不需要我們開發,而是早有人搞定了.(若是我能開發,我早就去谷歌開發者大會上做演講了= =) 這就是大名鼎鼎的 :==ajc編譯器==(他屬于AspectJ框架,可以單獨使用此框架寫個例子,可以加深理解)

1. 想象一下,有這么兩坨東西

┌────────────────────┐
|   Controller.java  |
├────────────────────┤           ┌─────────────────┐
|   Service.java     |           |  log.info.java  |
└────────────────────┘           └─────────────────┘

2. 然后開始編譯 : 編譯器開始把Service.java中的代碼編織成一個class文件.
3. ajc編譯器開始編譯 : ajc開始把log.info.java編織插入到service中.

┌────────────────────┐
|   Controller.java  |    _________________
├────────────────────┤ _/ log.info.java   |
|   Service.java     |  \ ________________|
└────────────────────┘

4. 就像上面,把log.info織入到這個這個方法中.
5. 最終形成的calss文件,就是這樣

┌───────────────┐
|   Controller  |
├───────────────┤
|   log.info... |
|   Service     |
└───────────────┘

成了,問題解決了.有了這個編譯器,前面的問題有迎刃而解. ==ps : ajc編譯器并不是唯一解決辦法==

那么問題又又來了,==面向切面是什么?== 也許你已經有答案了.

┌───────────────┐
|   Controller  |        ┌──────────────────────────────────┐
├───────────────┼──────> | 我們在這個角度寫代碼,就是面向切面.  |
|   Service     |        |                                  |
├───────────────┼──────> | 我們在這個角度寫代碼,就是面向切面.  |
|      Dao      |        └──────────────────────────────────┘
└───────────────┘

我們站在那條線的角度寫代碼,就是面向切面. 那條線,是不是將原本的代碼分成了兩個部分呢? 更形象一點

		┌───────────────┐
		|   Controller  |
		└───────────────┘
───────────────────────────────────── 這條線,像不像把整個代碼切開的一條線呢?那么這條線,就叫切面
───────────────────────────────────── 如 : 日志調用
───────────────────────────────────── 如 : 調用時間
───────────────────────────────────── 如 : 事務管理
		┌───────────────┐
		|   Service     |
		├───────────────┤
		|      Dao      |
		└───────────────┘

上面的每一個如,就是一個切面類,也相當于一個切面,畢竟沒有人規定我們必須只有一個切面不是?

面向切面是一種人們面對難題時的解決方案,他并不是一個新的語言或是新的技術. 他消除了面向對象的一系列編程陋習.或者說解決了面向對象的一些缺點.

到了這里,我相信有些人還是不太懂面向切面的意義或者作用是什么,沒關系,不要氣餒,你一定比我當時可聰明多了.請繼續往下看.

	 這張圖可能并不太能直觀的表達面向切面意義有多么重大.
	 ┌───────────────┐
	 |   Controller  |
	 └───────────────┘
	 ─────────────────────────
	 ┌───────────────┐
	 |   Service     |
	 ├───────────────┤
	 |      Dao      |
	 └───────────────┘
	
	 那么,這張圖呢?

     ┌────────────────┬────────────────┬────────────────┬────────────────┬────────────────┬────────────────┐
     |   Controller1  |   Controller2  |   Controller3  |   Controller4  |   Controller5  |   Controller6  |
     └────────────────┴────────────────┴────────────────┴────────────────┴────────────────┴────────────────┘
─────────────────────── 面向切面的方法,可以織入到所有的service中,而不需要改變service的代碼 ─────────────────────────
─────────────────────── 權限校驗 ───────────────────────────────────────────────────────────────────────────────
─────────────────────── 日志調用 ───────────────────────────────────────────────────────────────────────────────
─────────────────────── 調用時間 ───────────────────────────────────────────────────────────────────────────────
─────────────────────── 事務管理 ───────────────────────────────────────────────────────────────────────────────
     ┌────────────────┬────────────────┬────────────────┬────────────────┬────────────────┬────────────────┐
     |   Service1     |   Service2     |   Service3     |   Service4     |   Service5     |   Service6     |
     └────────────────┴────────────────┴────────────────┴────────────────┴────────────────┴────────────────┘
─────────────────────── 面向切面的方法,可以織入到所有的Dao中,而不需要改變Dao的代碼 ─────────────────────────────────
─────────────────────── 日志調用 ───────────────────────────────────────────────────────────────────────────────
─────────────────────── 調用時間 ───────────────────────────────────────────────────────────────────────────────
     ┌────────────────┬────────────────┬────────────────┬────────────────┬────────────────┬────────────────┐
     |      Dao1      |      Dao2      |      Dao3      |      Dao4      |      Dao5      |      Dao6      |
     └────────────────┴────────────────┴────────────────┴────────────────┴────────────────┴────────────────┘
	 
	 我只需要聲明一個類,就可以該類中的方法插入到任意類的位置	

有些人說,用代理模式就可以解決上面所說的編程時的一系列問題. 沒錯! 面向切面 ─── 是思想. 代理模式 ─── 是思想的實現.

二. 畫個圖片

上面畫過了

三. 寫個代碼

只講概念,后面講例子

四. 說個人話

切面的幾大概念

1.切面 (Aspect) :

拓展的類 概念 : Aspect 聲明類似于Java中的類聲明,在Aspect中會包含著一些切點以及相應的增強. 人話 : 創建一個類,這個類中的<增強>將插入到<目標對象>代碼中.

2.連接點 (Joint point) :

調用點 概念 : 表示在程序中明確定義的點,典型的包括方法調用,對類成員的訪問以及異常處理程序塊的執行等等,它自身還可以嵌套其它 joint point. 人話 : 被<切點>所包含的內容, 如切點為 userService.add()方法 : 連接點就是userService.add() 如切點為 com.xxx包下的所有service : com.xxx包下的所有service的任意一個方法 如切點為 com.xxx包下的所有add開頭的方法 : com.xxx包下的所有add開頭的方法

3.切點 (Pointcut):

在哪里增強 概念 : 表示一組<連接點>,這些 joint point 或是通過邏輯關系組合起來,或是通過通配、正則表達式等方式集中起來,它定義了相應的增強將要發生的地方.或是我們要織入的地方 人話 : 要往哪里插入 如 userService.add()方法 或 com.xxx包下的所有service方法 或 com.xxx包下的所有add開頭的方法

4.增強 (Advice) :

拓展方法 概念 : Advice 定義了在<切點>里面定義的程序點具體要做的操作,它通過 before、after 和 around 來區別是在每個<連接點>之前、之后還是代替執行的代碼. 人話 : 切面類中需要定義的,連接點方法調用前的拓展,之后的拓展,或者之前和之后的拓展.

5.目標對象 (Target) :

被增強的目標 概念 : 增強(Advice) 的目標對象.. 人話 : 被增強的目標

6.織入 (Weaving):

插入的動作 概念 : 將 Aspect 和其他對象連接起來, 并創建 Adviced object 的過程. 人話 : 將切面類插入進去

例如:
我們要在service的add方法里里增加日志
┌───────────────┐
|   Controller  |
└───────────────┘
─────────────────────────────────────    <-- com.xxx.service.UService  ─── <切點>
┌───────────────┐      ┌────────────┐    <-- log.info所在的類           ─── <切面>
| UService.add  |      |  log.info  |    <-- log.info方法就是           ─── <增強>
├───────────────┤      └────────────┘
|      Dao      |
└───────────────┘

UService.add的調用就是   ─── <連接點>
UService                ─── <目標對象>

到這里你應該理解什么是面向切面了,如果你還是不理解,不怕,可能是我的表達方式不適合你,全網有很多對于面向對象的優秀理解. 雖然篩選好文章需要時間,我可以幫你找出來,但其實在篩選的過程中,更是一個理解的過程.

關于如何用最通俗的方法講spring中的AOP就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

无极县| 玛多县| 承德县| 元阳县| 阿鲁科尔沁旗| 调兵山市| 图们市| 二连浩特市| 望江县| 门源| 海林市| 怀安县| 揭阳市| 融水| 丰镇市| 连州市| 南康市| 曲沃县| 万州区| 怀远县| 白银市| 安吉县| 曲松县| 桐城市| 祁东县| 湖南省| 汝阳县| 观塘区| 和平区| 河北省| 井冈山市| 都昌县| 明星| 定结县| 定南县| 台中市| 泰和县| 郑州市| 罗平县| 永嘉县| 靖远县|