Go-Web框架中AOP方案的實現(xiàn)方式
寫在前面
最近不是在跟兔兔的七天系列嘛,目前是跟到了Web框架(好吧,這才是剛開始)。關于Web框架這一塊,兔兔的文章是跟完了,也做完了,現(xiàn)在是在做總結??偨Y到AOP方案的時候,就有點蒙圈了,所以打算寫下這篇文章記錄總結兩種AOP方案。
Gin的AOP實現(xiàn)方案
其實兔兔的AOP方案和Gin的AOP方案很相似。都是通過下標控制一個中間件進入到下一個中間件的。當下標大于中間件的個數(shù)的時候,整個中間件就會往回執(zhí)行

特點
- 中間件是是現(xiàn)在上下文中的
- 通過下標進入下一個中間件
具體看下Gin的實現(xiàn)源碼

具體看下兔兔的實現(xiàn)源碼

其實是很類似的。對于這個方法,理解起來是沒什么難度的。下面我就講講這個AOP方案的實現(xiàn)流程吧。
中間件注冊是通過Use方法,這個方法是RouterGroup路由組提供的,在Gin中實際是抽象出了一個接口


2. 被注冊的中間件是保存在路由組的屬性中,上圖中圈住的部分
3. 在ServerHTTP方法中匹配命中的路由視圖函數(shù)、符合條件的中間件。

4. 將命中的視圖函數(shù)添加到中間件列表中

5. 執(zhí)行Next方法。每當中間件函數(shù)中有Next方法,就會再一次進入到Next方法,由于選取要執(zhí)行的中間件是通過c.index控制的,每次進來都會自加1。當所有的中間件都執(zhí)行完了,index的值就超過了中間件的個數(shù)。也就是退出了遞歸。遞歸最底層的方法都執(zhí)行完成了,就開始一層一層返回了。

責任鏈制的AOP實現(xiàn)原理
對于責任鏈制的AOP方案,原理和洋蔥模式是一樣,(順帶提一下,Gin的設計模式叫做洋蔥模式)。它的任務是一直構建"視圖函數(shù)",最終構建成這樣的形式
func m() {
fmt.Println("coming middleware1...")
func() {
fmt.Println("coming middleware2...")
func() {
fmt.Println("coming middleware3...")
func() {
fmt.Println("coming middleware4...")
func() {
fmt.Println("coming middleware5...")
func() {
}()
fmt.Println("outing middleware5...")
}()
fmt.Println("outing middleware4...")
}()
fmt.Println("outing middleware3...")
}()
fmt.Println("outing middleware2...")
}()
fmt.Println("outing middleware1...")
}但是上述這種形式太不優(yōu)雅了,我們就使用一個責任鏈的設計模式來實現(xiàn)、優(yōu)化,但是精髓就是構建出這種樣子。

注意
- 我們需要對中間件進行一個包裝,就是說對中間件的函數(shù)簽名進行一個包裝
- 我們的視圖函數(shù)不用變
- 可以理解的是中間件函數(shù)就是生成一個視圖函數(shù),只不過生成的視圖函數(shù)嵌入了一些別的通用邏輯
// 視圖函數(shù)簽名 type HandleFunc func(ctx *Context) // 中間件函數(shù)簽名 type Middleware func(next HandleFunc) HandeFunc
下文我統(tǒng)一將中間函數(shù)和命中的視圖函數(shù)叫做中間件。不過命中的視圖函數(shù)會加上特殊二字
中間件函數(shù)簽名解釋一下:
- 參數(shù)
next是下一次需要的中間件邏輯 - 返回值是一個特殊的中間件,這個就是當前這個中間件的邏輯
具體的一個中間件示例代碼
func Logger() Middleware {
return func(next HandleFunc) HandleFunc {
return func(ctx *Context){
fmt.Println("請求來了")
next(ctx)
fmt.Println("請求走了")
}
}
}
解釋示例代碼:
Logger函數(shù)返回一個Middleware函數(shù)。返回一個視圖函數(shù)構造器fmt.Println("請求來了")和fmt.Println("請求走了")兩行代碼分別嵌在next下一個需要執(zhí)行的中間件邏輯
上述已經(jīng)講完了關于責任鏈制的AOP方法的具體原理。但是到這里還不夠,這只是原理,還沒有和我們的框架進行適配。接下來就具體講講怎么和咱們的框架進行適配。
責任鏈制的AOP方案應用
首先還是需要定義好視圖函數(shù)、中間件函數(shù)的簽名
// 視圖函數(shù)簽名 type HandleFunc func(ctx *Context) // 中間件函數(shù)簽名 type Middleware func(next HandleFunc) HandeFunc
我們的AOP是集成在server層面上的,在Gin中,AOP是集成在Context上下文層面上面的。其實這個沒有多大的區(qū)別的,無非是設計者的設計思想而已。
說我們的AOP是集成在server層面其實還不太準確,準確來說是在路由組RouterGroup上的。
路由組RouterGroup定義一個屬性保存當前組的所有中間件

2. 路由組RouterGroup提供一個方法Use注冊中間件

3. 匹配路由的時候需要找出當前路由所屬哪個組,并將其所有的中間件抽離出來

4. 組裝中間件
在組裝中間價的時候,我們需要注意:
- 我們注冊的中間件是有順序的
- 我們執(zhí)行的中間件也是要有順序的
- 先注冊先執(zhí)行前半部分

基于上述的注意事項,我們組裝的中間件應該是從后往前組裝的。這里需要花點時間想想
我們可以這樣想,如果是按照正向的順序遍歷middlewares的話,最后的handler應該是最后一個注冊的中間件才對。這和我們的期待是完全相反的,從這也就能解釋為什么我們需要從后往前組裝中間件了。只有這樣,最后handler才是我們第一個注冊的中間件方法。
最后就執(zhí)行handler方法即可。

總結
- 基于洋蔥模型的AOP方案和基于責任鏈制的AOP方案本質(zhì)沒有區(qū)別
- Gin的AOP是集成在上下文中,我們的是集成在
RouterGroup上。兩種方式?jīng)]有區(qū)別
到此這篇關于Go-Web框架中AOP方案的實現(xiàn)方式的文章就介紹到這了,更多相關Go AOP實現(xiàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
使用dep 配置golang 開發(fā)環(huán)境的操作方法
下面小編就為大家?guī)硪黄褂胐ep 配置golang 開發(fā)環(huán)境的操作方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-09-09
go panic時如何讓函數(shù)返回數(shù)據(jù)?
今天小編就為大家分享一篇關于go panic時如何讓函數(shù)返回數(shù)據(jù)?,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-04-04

