beego 例子_beego框架代码分析
前言
也許beego框架在國內(nèi)應(yīng)該是眾多PHPer轉(zhuǎn)go的首選,因?yàn)閎eego的MVC、ORM、完善的中文文檔讓PHPer們得心應(yīng)手,毫無疑問我也是。這種感覺就像當(dāng)年入門PHP時使用ThinkPHP一樣。
也許隨著你的認(rèn)知的提升,你會討厭現(xiàn)在東西,比如某一天你可能慢慢的開始討厭beego,你會發(fā)現(xiàn)go語言里包的真正意義,你開始反思MVC真的適合go嗎,或者你開始覺著ORM在靜態(tài)語言里的雞肋,等等。我只想說:“也許你成長了~”。但是這些都不重要,每一個受歡迎的事物自然有我們值的學(xué)習(xí)的地方。今天這篇文章很簡單,像一篇筆記,記錄了我這幾天抽空讀beego源碼的記錄。
如何讀一個框架?
毫無疑問讀go的框架和PHP框架也是一樣的:
配置加載:如何加載配置文件的。
路由:分析框架如何通過URI執(zhí)行對應(yīng)業(yè)務(wù)的。
ORM:ORM如何實(shí)現(xiàn)的。
這里(1.)和(3.)無非就是加載個文件和sql解析器的實(shí)現(xiàn),我就忽略了,重點(diǎn)就看看路由的實(shí)現(xiàn)。
安裝
簡單帶過:
// Step1: 安裝beego
go get github.com/astaxie/beego
// Step2: 安裝bee
go get github.com/beego/bee
// Step3: 用bee工具創(chuàng)建一個新的項目
bee new beego-code-read
代碼分析
go有自己實(shí)現(xiàn)的http包,大多go框架也是基于這個http包,所以看beego之前我們先補(bǔ)充或者復(fù)習(xí)下這個知識點(diǎn)。如下:
go如何啟動一個http server
package main
import (
// 導(dǎo)入net/http包
"net/http"
)
func main() {
// ------------------ 使用http包啟動一個http服務(wù) 方式一 ------------------
// *http.Request http請求內(nèi)容實(shí)例的指針
// http.ResponseWriter 寫http響應(yīng)內(nèi)容的實(shí)例
http.HandleFunc("/v1/demo", func(w http.ResponseWriter, r *http.Request) {
// 寫入響應(yīng)內(nèi)容
w.Write([]byte("Hello TIGERB !\n"))
})
// 啟動一個http服務(wù)并監(jiān)聽8888端口 這里第二個參數(shù)可以指定handler
http.ListenAndServe(":8888", nil)
}
// 測試我們的服務(wù)
// --------------------
// 啟動:bee run
// 訪問: curl "http://127.0.0.1:8888/v1/demo"
// 響應(yīng)結(jié)果:Hello TIGERB !
ListenAndServe是對http.Server的進(jìn)一步封裝,除了上面的方式,還可以使用http.Server直接啟服務(wù),這個需要設(shè)置Handler,這個Handler要實(shí)現(xiàn)Server.Handler這個接口。當(dāng)請求來了會執(zhí)行這個Handler的ServeHTTP方法,如下:
package main
// 導(dǎo)入net/http包
import (
"net/http"
)
// DemoHandle server handle示例
type DemoHandle struct {
}
// ServeHTTP 匹配到路由后執(zhí)行的方法
func (DemoHandle) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello TIGERB !\n"))
}
func main() {
// ------------------ 使用http包的Server啟動一個http服務(wù) 方式二 ------------------
// 初始化一個http.Server
server := &http.Server{}
// 初始化handler并賦值給server.Handler
server.Handler = DemoHandle{}
// 綁定地址
server.Addr = ":8888"
// 啟動一個http服務(wù)
server.ListenAndServe()
}
// 測試我們的服務(wù)
// --------------------
// 啟動:bee run
// 訪問: curl "http://127.0.0.1:8888/v1/demo"
// 響應(yīng)結(jié)果:Hello TIGERB !
beego路由分析
接下里我們開始看beego的代碼。拿訪問"http://127.0.0.1:8080/"來說,對于beego代碼來說有三個關(guān)鍵點(diǎn),分別如下:
啟動:main.go -> beego.Run()
注冊路由:routersrouter.go -> beego.Router("/", &controllers.MainController{})
控制器:controllersdefault.go -> Get()
下面來看3個關(guān)鍵點(diǎn)的詳細(xì)分析:
beego.Run()主要的工作
// github.com/astaxie/beego/beego.go
func Run(params ...string) {
// 啟動http服務(wù)之前的一些初始化 忽略 往下看
initBeforeHTTPRun()
// http服務(wù)的ip&port設(shè)置
if len(params) > 0 && params[0] != "" {
strs := strings.Split(params[0], ":")
if len(strs) > 0 && strs[0] != "" {
BConfig.Listen.HTTPAddr = strs[0]
}
if len(strs) > 1 && strs[1] != "" {
BConfig.Listen.HTTPPort, _ = strconv.Atoi(strs[1])
}
}
// 又一個run 往下看
BeeApp.Run()
}
// github.com/astaxie/beego/app.go
func (app *App) Run(mws ...MiddleWare) {
// ... 省略
// 看了下這里app.Server的類型就是*http.Server 也就是說用的原生http包 且是上面“go如何啟動一個http server”中的第二種方式
app.Server.Handler = app.Handlers
// ... 省略
if BConfig.Listen.EnableHTTP {
go func() {
app.Server.Addr = addr
logs.Info("http server Running on http://%s", app.Server.Addr)
// 默認(rèn)配置false不強(qiáng)制tcp4
if BConfig.Listen.ListenTCP4 {
//...
// 忽略 默認(rèn)false
} else {
// 關(guān)鍵點(diǎn) ListenAndServe: app.Server的類型就是*http.Server 所以這里就啟動了http服務(wù)
if err := app.Server.ListenAndServe(); err != nil {
logs.Critical("ListenAndServe: ", err)
time.Sleep(100 * time.Microsecond)
endRunning
}
}
}()
}
// 阻塞到服務(wù)啟動
}
// 看到這里http已經(jīng)啟動了 而且是注冊Handler的方式
接著去找這個Handler的ServeHTTP方法,通過上面的這段代碼app.Server.Handler = app.Handlers,我們找到了下面的定義,Handler即是ControllerRegister的值,所以每次親求來了就會去執(zhí)行ControllerRegister.ServeHTTP(rw http.ResponseWriter, r *http.Request)。
// src/github.com/astaxie/beego/app.go
func init() {
// 調(diào)用 創(chuàng)建beego框架實(shí)例的方法
BeeApp = NewApp()
}
// App結(jié)構(gòu)體
type App struct {
// 關(guān)鍵的請求回調(diào)Handler
Handlers *ControllerRegister
// http包的服務(wù)
Server *http.Server
}
func NewApp() *App {
// 初始化http handler
cr := NewControllerRegister()
// 創(chuàng)建beego 實(shí)例
app := &App{Handlers: cr, Server: &http.Server{}}
return app
}
通過我們追beego.Run()的代碼,目前我們得到的結(jié)論就是:
使用的http包啟動的服務(wù)
沒有使用http.HandleFun()的定義路由策略,而是注冊Handler的方式
所以beego就是通過beego.Router()自己管理路由,如果http請求來了,回調(diào)ControllerRegister.ServeHTTP(rw http.ResponseWriter, r *http.Request)方法,在ControllerRegister.ServeHTTP(rw http.ResponseWriter, r *http.Request)方法中去匹配路由并執(zhí)行對應(yīng)的controller 也就是beegoControllerInterface類型的控制器的方法,比如RESTFUL或者自定義啊等。
beego.Router() 如何注冊路由
首先路由文件是如何加載的,我們發(fā)現(xiàn)在main.go文件里導(dǎo)入了路由包:
package main
import (
// 導(dǎo)入routers包 只執(zhí)行init方法
_ "beego-code-read/routers"
"github.com/astaxie/beego"
)
func main() {
beego.Run()
}
上面我們啟動了http服務(wù),接著關(guān)鍵就是beego.Router()如何注冊路由了。追了下代碼如下:
beego.Router()
-> BeeApp.Handlers.Add(rootpath, c, mappingMethods...)
-> ControllerRegister.addWithMethodParams(pattern, c, nil, mappingMethods...)
-> ControllerRegister.addToRouter(method, pattern string, r *ControllerInfo)
-> *Tree.AddRouter(pattern string, runObject interface{})
最后就是在*Tree.AddRouter()完成了路由注冊,這里的代碼邏輯暫時就先不看了,至此這個beego框架的流程就其本理順了,最后我們在回頭總結(jié)下整個流程如下圖:
備注:go導(dǎo)入包相當(dāng)于入棧過程,先import后執(zhí)行init
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的beego 例子_beego框架代码分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Win11系统怎么取消登录密码 Win1
- 下一篇: 邮票的孔怎么做出来的_金银花茶是怎么做出