最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文詳解Golang的中間件設(shè)計(jì)模式

 更新時(shí)間:2023年03月06日 14:49:49   作者:白象孫國帥  
最近在看一些rpc框架的使用原理和源碼的時(shí)候,對中間件的實(shí)現(xiàn)非常感興趣,所以這篇文章就來和大家聊聊Golang的中間件設(shè)計(jì)模式,希望對大家有所幫助

背景

記錄一下自己在go開發(fā)和學(xué)習(xí)上的一些筆記

最近在看一些rpc框架的使用原理和源碼的時(shí)候,對中間件的實(shí)現(xiàn)非常感興趣,然后也看了一下grpc的中間件的用法,也看了別的框架的中間件的設(shè)計(jì),感覺grpc的還算是比較容易弄懂,于是記錄一下這個(gè)常用中間件的實(shí)現(xiàn)的一個(gè)原理的demo(吐槽一下其他的rpc框架分為inbound和outbound的middleware感覺好像有點(diǎn)復(fù)雜化了,所以我也不知道哪種設(shè)計(jì)會比較好,樓主是java出身,所以對反射走aop的那種模式比較熟悉,對鏈?zhǔn)秸{(diào)用的middleware有點(diǎn)不太熟悉,當(dāng)然現(xiàn)在已經(jīng)熟悉了)

Demo

所以接下來我們就來看看demo吧 首先先定義好中間件的類型,這里我就簡單定義為以下的格式

type middleware func(ctx context.Context, req interface{}, handler endpoint) (resp interface{}, err error)
  • ctx: 協(xié)程間通信帶著
  • req: 請求的格式,這里圖簡便,直接interface{}類型
  • resp: 同req
  • err: error

handler: endpoint類型,真正用來發(fā)起請求的一個(gè)處理方法或者是經(jīng)過N層中間件包裝的后的發(fā)起請求的處理方法

type endpoint func(ctx context.Context, req interface{}) (resp interface{}, err error)
//ctx: 協(xié)程間通信帶著 

//req: 請求的格式,這里圖簡便,直接interface{}類型
//resp: 同req  
//err: error

然后既然我們要將上方的endpoint進(jìn)行包裝然后產(chǎn)生一個(gè)新的endpoint那么也就是需要一個(gè)函數(shù)去做一步的事情,input是endpoint,ouput也是endpoint

type warp func(endpoint) endpoint //就是這個(gè)warp函數(shù)

然后我們通過每次調(diào)用這個(gè)warp的定義去生成一個(gè)新的endpoint就可以產(chǎn)生一個(gè)類似于dfs鏈?zhǔn)秸{(diào)用的一個(gè)中間件的過程,因?yàn)閷粚犹滓粚拥?code>endpoint下去,然后當(dāng)最后一層有返回了以后就可以接著返回了,然后不斷的彈棧回去最開始的地方,因?yàn)槲覀冎虚g件的實(shí)現(xiàn)必然是要調(diào)用handler的

func(ctx context.Context, req interface{}, handler endpoint) (resp interface{}, err error) {
		fmt.Printf("before1\n")
		resp, err = handler(ctx, req)
		fmt.Printf("end1\n")
		return
}

// handler0
var handler endpoint = func(ctx context.Context, req interface{}) (resp interface{}, err error) {
	fmt.Printf("make msg\n")
	return nil, nil
} 
// middleware
var md Middleware = func(ctx context.Context, req interface{}, handler endpoint) (resp interface{}, err error) {
		fmt.Printf("before1\n")
		resp, err = handler(ctx, req)
		fmt.Printf("end1\n")
		return
}
// warp ->> handler1
handler = warp(func(e endpoint) endpoint {
		return func(ctx context.Context, req interface{}) (resp interface{}, err error) {
				return md(ctx, req, e)
			}
		})(handler)

驗(yàn)證結(jié)論

package main

import (
	"context"
	"fmt"
)

type endpoint func(ctx context.Context, req interface{}) (resp interface{}, err error)

type middleware func(ctx context.Context, req interface{}, handler endpoint) (resp interface{}, err error)

type warp func(endpoint) endpoint

func main() {
	mds := []middleware{}
	mds = append(mds, func(ctx context.Context, req interface{}, handler endpoint) (resp interface{}, err error) {
		fmt.Printf("before1\n")
		resp, err = handler(ctx, req)
		fmt.Printf("end1\n")
		return
	})
	mds = append(mds, func(ctx context.Context, req interface{}, handler endpoint) (resp interface{}, err error) {
		fmt.Printf("before2\n")
		resp, err = handler(ctx, req)
		fmt.Printf("end2\n")
		return
	})
	var handler endpoint = func(ctx context.Context, req interface{}) (resp interface{}, err error) {
		fmt.Printf("make msg\n")
		return nil, nil
	}
	for i := len(mds) - 1; i >= 0; i-- {
		handler = warp(func(e endpoint) endpoint {
			// 由于go的機(jī)制問題如果不用tmp去存下當(dāng)前的i,那么mds[i]就會取最終的那一個(gè),就會溢出,所以在return前先保存一下i的量,然后每一個(gè)stack去存的變量就是對的
			cur := i
			return func(ctx context.Context, req interface{}) (resp interface{}, err error) {
				return mds[cur](ctx, req, e)
			}
		})(handler)
	}
	resp, err := handler(context.Background(), "ster")
	if resp != nil && err != nil {
		return
	}
}

結(jié)果是

before1
before2
make msg
end2
end1

結(jié)論:感覺有函數(shù)指針的語言都可以用這一套去實(shí)現(xiàn)一個(gè)中間件

以上就是一文詳解Golang的中間件設(shè)計(jì)模式的詳細(xì)內(nèi)容,更多關(guān)于Golang中間件設(shè)計(jì)模式的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • golang執(zhí)行命令操作 exec.Command

    golang執(zhí)行命令操作 exec.Command

    這篇文章主要介紹了golang執(zhí)行命令操作 exec.Command,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • 深入刨析Golang-map底層原理

    深入刨析Golang-map底層原理

    這篇文章主要介紹了深入刨析Golang-map底層原理,Go 語言的 map 的使用非常簡易, 但其內(nèi)部實(shí)現(xiàn)相對比較復(fù)雜,文中有相關(guān)的代碼示例,,需要的朋友可以參考下
    2023-05-05
  • Go 語言的指針的學(xué)習(xí)筆記

    Go 語言的指針的學(xué)習(xí)筆記

    這篇文章主要介紹了Go 語言的指針的學(xué)習(xí)筆記,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-09-09
  • 淺談Golang是如何讀取文件內(nèi)容的(7種)

    淺談Golang是如何讀取文件內(nèi)容的(7種)

    這篇文章主要介紹了淺談Golang是如何讀取文件內(nèi)容的,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • Go?Singleflight導(dǎo)致死鎖問題解決分析

    Go?Singleflight導(dǎo)致死鎖問題解決分析

    這篇文章主要為大家介紹了Go?Singleflight導(dǎo)致死鎖問題解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • Go逃逸分析示例詳解

    Go逃逸分析示例詳解

    這篇文章主要為大家介紹了Go逃逸分析示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • go code review 代碼調(diào)試

    go code review 代碼調(diào)試

    這篇文章主要為大家介紹了go code review 代碼調(diào)試方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • golang中使用proto3協(xié)議導(dǎo)致的空值字段不顯示的問題處理方案

    golang中使用proto3協(xié)議導(dǎo)致的空值字段不顯示的問題處理方案

    這篇文章主要介紹了golang中使用proto3協(xié)議導(dǎo)致的空值字段不顯示的問題處理方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • golang使用sync.singleflight解決熱點(diǎn)緩存穿透問題

    golang使用sync.singleflight解決熱點(diǎn)緩存穿透問題

    在go的sync包中,有一個(gè)singleflight包,里面有一個(gè)?singleflight.go文件,代碼加注釋,一共200行出頭,通過?singleflight可以很容易實(shí)現(xiàn)緩存和去重的效果,避免重復(fù)計(jì)算,接下來我們就給大家詳細(xì)介紹一下sync.singleflight如何解決熱點(diǎn)緩存穿透問題
    2023-07-07
  • Golang使用DuckDB查詢Parquet文件數(shù)據(jù)的操作代碼

    Golang使用DuckDB查詢Parquet文件數(shù)據(jù)的操作代碼

    本文介紹DuckDB查詢Parquet文件的典型應(yīng)用場景,掌握DuckDB會讓你的產(chǎn)品分析能力更強(qiáng),相反系統(tǒng)運(yùn)營成本相對較低,為了示例完整,我也提供了如何使用Python導(dǎo)出MongoDB數(shù)據(jù),需要的朋友可以參考下
    2025-01-01

最新評論

三原县| 紫云| 德钦县| 鲁山县| 临高县| 和林格尔县| 平定县| 滕州市| 连平县| 彩票| 丰原市| 湖口县| 广丰县| 栾城县| 崇义县| 昌江| 津市市| 华宁县| 呼图壁县| 广元市| 图们市| 巩义市| 新兴县| 沂南县| 汝州市| 玉屏| 温泉县| 仁寿县| 霍山县| 梅州市| 昌黎县| 且末县| 沧州市| 吐鲁番市| 黄骅市| 阿坝县| 卢氏县| 吴旗县| 清镇市| 哈密市| 太保市|