標籤:次數 重複 4.4 modified asp 概念 res 磁軌 模組
在軟體開發中, 散佈於應用中多處的功能被稱為橫切關注點,通常來講, 這些橫切關注點從概念上是與應用的商務邏輯相分離的(但是往往會直接嵌入到應用的商務邏輯之中),例如日誌、 安全和交易管理。把這些橫切關注點與商務邏輯相分離正是面向切面編程(AOP) 所要解決的問題。
橫切關注點可以被模組化為特殊的類,這些類被稱為切面(aspect)
通知(Advice)
它必須要完成的工作。 在AOP術語中, 切面的工作被稱為通知。通知定義了切面是什麼以及何時調用。 除了描述切面要完成的工作,通知還解決了何時執行這個工作的問題。 它應該應用在某個方法被調用之前? 之後? 之前和之後都調用? 還是只在方法拋出異常時調用
Spring切面可以應用5種類型的通知:
前置通知(Before) : 在目標方法被調用之前調用通知功能;
後置通知(After) : 在目標方法完成之後調用通知, 此時不會關
心方法的輸出是什麼;
返回通知(After-returning) : 在目標方法成功執行之後調用通
知;
異常通知(After-throwing) : 在目標方法拋出異常後調用通知;
環繞通知(Around) : 通知包裹了被通知的方法, 在被通知的方
法調用之前和調用之後執行自訂的行為。
連接點(Join point)
我們的應用可能也有數以千計的時機應用通知。 這些時機被稱
為連接點。 連接點是在應用執行過程中能夠插入切面的一個點。 這個
點可以是調用方法時、 拋出異常時、 甚至修改一個欄位時。 切面代碼
可以利用這些點插入到應用的正常流程之中, 並添加新的行為。
切點(Poincut)
如果說通知定義了切面的“什麼”和“何時”的話, 那麼切點就定義了“何處”。 切點的定義會匹配通知所要織入的一個或多個連接點。 我們通常使用明確的類和方法名稱, 或是利用Regex定義所匹配的類和方法名稱來指定這些切點。 有些AOP架構允許我們建立動態切點, 可以根據運行時的決策(比如方法的參數值) 來決定是否應用通知。
切面(Aspect)
切面是通知和切點的結合。 通知和切點共同定義了切面的全部內容——它是什麼, 在何時和何處完成其功能
引入(Introduction)
引入允許我們向現有的類添加新方法或屬性。 例如, 我們可以建立一個Auditable通知類, 該類記錄了對象最後一次修改時的狀態。 這很簡單, 只需一個方法, setLastModified(Date), 和一個執行個體變數來儲存這個狀態。 然後, 這個新方法和執行個體變數就可以被引入到現有的類中, 從而可以在無需修改這些現有的類的情況下, 讓它們具有新的行為和狀態。
織入(Weaving)
織入是把切面應用到目標對象並建立新的代理對象的過程。 切面在指定的連接點被織入到目標對象中。 在目標對象的生命週期裡有多個點可以進行織入:編譯期: 切面在目標類編譯時間被織入。 這種方式需要特殊的編譯器。 AspectJ的織入編譯器就是以這種方式織入切面的。類載入期: 切面在目標類載入到JVM時被織入。 這種方式需要特殊的類載入器(ClassLoader) , 它可以在目標類被引入應用之前增強該目標類的位元組碼。 AspectJ 5的載入時織入(load-timeweaving, LTW) 就支援以這種方式織入切面。運行期: 切面在應用啟動並執行某個時刻被織入。 一般情況下, 在織入切面時, AOP容器會為目標對象動態地建立一個代理對象。Spring AOP就是以這種方式織入切面的
4.2.1 編寫切點
我們定義一個Performance介面
假設我們想編寫Performance的perform()方法觸發的通知
這個運算式能夠設定當perform()方法執行時觸發通知的調用
現在假設我們需要配置的切點僅匹配concert包。 在此情境下, 可以使用within()指標來限制匹配
因為“&”在XML中有特殊含義, 所以在Spring的XML配置裡面描述切點時, 我們可以使用and來代替“&&”。 同樣, or和not可以分別用來代替“||”和“!”。
4.2.2 在切點中選擇bean
4.3.1 定義切面
Audience類, 它定義了我們所需的一個切面
@Aspect 註解 聲明為一個切面類和POJO。
通過@Pointcut註解聲明頻繁使用的切點運算式
{erformance方法重複了N次
Audience類依然是一個POJO。 我們能夠像使用其他的Java類那樣調用它的方法, 它的方法也能夠獨立地進行單元測試, 這與其他的Java類並沒有什麼區別。 Audience只是一個Java類, 只不過它通過註解表明會作為切面使用而已。
像其他的Java類一樣, 它可以裝配為Spring中的bean
在JavaConfig中啟用AspectJ註解的自動代理
在XML中, 通過Spring的aop命名空間啟用AspectJ自動代理
4.3.2 建立環繞通知
它能夠讓你所編寫的邏輯將被通知的目標方法完全封裝起來。 實際上就像在一個通知方法中同時編寫前置通知和後置通知。
4.3.3 處理通知中的參數
為了記錄每個磁軌所播放的次數, 我們建立了TrackCounter類,它是通知playTrack()方法的一個切面。 下面的程式清單展示了這個切面
需要關注的是切點運算式中的args(trackNumber)限定符。 它表明傳遞給playTrack()方法的int型別參數也會傳遞到通知中去。 參數的名稱trackNumber也與切點方法簽名中的參數相匹配。
這個通知方法是通過@Before註解和命名切點trackPlayed(trackNumber)定義的。 切點定義中的
參數與切點方法中的參數名稱是一樣的, 這樣就完成了從命名切點到通知方法的參數轉移
4.4 在XML中聲明切面
第一個需要注意的事項是大多數的AOP配置元素必須在<aop:config>元素的上下文內使用
基於AspectJ註解的通知中, 當發現這種類型的重複時, 我們使用@Pointcut註解消除了這些重複的內容。 而在基於XML的切面聲明中, 我們需要使用<aop:pointcut>元素。 如下的XML展現了如何將通用的切點運算式抽取到一個切點聲明中, 這樣這個聲明就能在所有的通知元素中使用了
使用<aop:pointcut>定義命名切點
唯一的差別在於這裡使用and關鍵字而不是“&&”(因為在XML中, “&”符號會被解析為實體的開始)
第5章 構建Spring Web應用程式
5.1.1 跟蹤Spring MVC的請求
1)在請求離開瀏覽器時 , 會帶有使用者所請求內容的資訊, 至少會包含請求的URL。 但是還可能帶有其他的資訊, 例如使用者提交的表單資訊。
2)請求旅程的第一站是Spring的DispatcherServletSpring。 MVC所有的請求都會通過一個前端控制器(front controller) Servlet。 前端控制器是常用的Web應用程式模式, 在這裡一個單一實例的Servlet將請求委託給應用程式的其他組件來執行實際的處理。 在Spring MVC中, DispatcherServlet就是前端控制器。
DispatcherServlet的任務是將請求發送給Spring MVC控制器(controller) 。 控制器是一個用於處理請求的Spring組件。 在典型的應用程式中可能會有多個控制器, DispatcherServlet需要知道應該將請求發送給哪個控制器。 所以DispatcherServlet以會查詢一個或多個處理器映射(handler mapping) 來確定請求的下一站在哪裡。 處理器映射會根據請求所攜帶的URL資訊來進行決策
3)一旦選擇了合適的控制器, DispatcherServlet會將請求發送給選中的控制器 。 到了控制器, 請求會卸下其負載(使用者提交的資訊) 並耐心等待控制器處理這些資訊。 (實際上, 設計良好的控制器本身只處理很少甚至不處理工作, 而是將商務邏輯委託給一個或多個服務物件進行處理。 )
控制器在完成邏輯處理後, 通常會產生一些資訊, 這些資訊需要返回給使用者並在瀏覽器上顯示。 這些資訊被稱為模型(model) 。 不過僅僅給使用者返回原始的資訊是不夠的——這些資訊需要以方便使用的方式進行格式化, 一般會是HTML。 所以, 資訊需要發送給一個視圖(view) , 通常會是JSP
4)控制器所做的最後一件事就是將模型資料打包, 並且標示出用於渲染輸出的視圖名。 它接下來會將請求連同模型和視圖名發送回DispatcherServlet 。
這樣, 控制器就不會與特定的視圖相耦合, 傳遞給DispatcherServlet的視圖名並不直接表示某個特定的JSP。 實際上, 它甚至並不能確定視圖就是JSP。 相反, 它僅僅傳遞了一個邏輯名稱, 這個名字將會用來尋找產生結果的真正視圖。 DispatcherServlet將會使用視圖解析器(view resolver)來將邏輯視圖名匹配為一個特定的視圖實現, 它可能是也可能不是JSP。
5)既然DispatcherServlet已經知道由哪個視圖渲染結果, 那請求的任務基本上也就完成了。 它的最後一站是視圖的實現(可能是JSP) , 在這裡它交付模型資料。 請求的任務就完成了。 視圖將使用模型資料渲染輸出, 這個輸出會通過響應對象傳遞給用戶端(不會像聽上去那樣寫入程式碼) 。
(來換項目系列)Spring學習筆記(3)