golang 中的中介軟體技術
阿新 • • 發佈:2020-06-29
golang中很多網路相關的庫都使用到了一種 middleware
的程式設計技巧,包括 rpc 和 http。但是這種技巧剛接觸很容易搞不清楚概念,在這裡記錄一下我的理解。
以rpc框架 kite 為例 github地址
kite 作為一個rpc框架,提供了 middleware 的介面,保證多個 rpc 請求可以進行共同的一些配置,包括 超時,LB,日誌記錄等等。具體程式碼如下:
// EndPoint represent one method for calling from remote. type EndPoint func(ctx context.Context, req interface{}) (resp interface{}, err error) // Middleware deal with input EndPoint and output EndPoint type Middleware func(EndPoint) EndPoint // Chain connect middlewares into one middleware. func Chain(outer Middleware, others ...Middleware) Middleware { return func(next EndPoint) EndPoint { for i := len(others) - 1; i >= 0; i-- { next = others[i](next) } return outer(next) } }
然後是我自己寫的一個例子:
func MW1(next EndPoint) EndPoint { return func(ctx context.Context, req interface{}) (resp interface{}, err error) { ctx, cancel := context.WithTimeout(ctx, time.Second) fmt.Printf("Enter MW1\n") defer cancel() return next(ctx, req) } } func MW2(next EndPoint) EndPoint { return func(ctx context.Context, req interface{}) (resp interface{}, err error) { fmt.Printf("Enter MW2\n") return next(ctx, req) } } func real(ctx context.Context, req interface{}) (resp interface{}, err error) { fmt.Printf("Enter real. req: %v\n", req) return 1, nil } func main() { var mw = Chain(MW1, MW2) fmt.Printf("finish calling chain\n") var resp, err = mw(real)(context.Background(), "hello") fmt.Printf("resp: %v error: %v\n", resp, err) }
最終的列印結果:
finish calling chain
Enter other 0: 0x10a0040
Enter MW1
Enter MW2
Enter real. req: hello
resp: 1 error: <nil>
這裡的 EndPoint 和 Middleware 可以這麼理解:
EndPoint 是一個處理單元,而 Middleware 可以理解為對一串處理單元的包裝,最終適配另一個 EndPoint。如圖:
其中 Middleware1 就是藍色的,它包含了兩個 EndPoint,Middleware2 是綠色的,它包含了後面兩個 EndPoint,Middleware3 是黃色的,它包含了 Middleware1 和 Middleware2 兩個合起來的處理邏輯,也就是說可以通過呼叫 Chain(Middleware1, Middleware2)
千萬不能將 EndPoint 之間的線認為是 Middleware,因為一個 Middleware 是包含了多個 EndPoint 的。同時,從編碼的角度來說,一般中間節點的 EndPoint 邏輯都會寫在 Middleware 的匿名函式裡面。
最終呼叫一箇中間件時,需要傳入一個“葉子”EndPoint,也就是上圖中的 EndPoint n,這個EndPoint一般包含了真正的處理邏輯。