golang代碼執行順序


一:首先man.go,整個程序的入口

func main() {
    beego.Run()
}

然后beego.run()代碼

復制代碼
// Run beego application.
// beego.Run() default run on HttpPort
// beego.Run(":8089") // beego.Run("127.0.0.1:8089") func Run(params ...string) { if len(params) > 0 && params[0] != "" { strs := strings.Split(params[0], ":") if len(strs) > 0 && strs[0] != "" { HttpAddr = strs[0] } if len(strs) > 1 && strs[1] != "" { HttpPort, _ = strconv.Atoi(strs[1]) } } initBeforeHttpRun() if EnableAdmin { go beeAdminApp.Run() } BeeApp.Run() }
復制代碼

可以看出來,beego.run()可以帶參數。

beego.run()在默認的主機、端口號上運行,beego.run(port)在給定的端口號、默認的主機上運行。beego.run(addr:post)在給定的主機和端口上運行。

下面看看initBeforeHttpRun()的代碼。

復制代碼
func initBeforeHttpRun() {
    // if AppConfigPath not In the conf/app.conf reParse config if AppConfigPath != filepath.Join(AppPath, "conf", "app.conf") { err := ParseConfig() if err != nil && AppConfigPath != filepath.Join(workPath, "conf", "app.conf") { // configuration is critical to app, panic here if parse failed panic(err) } } // do hooks function for _, hk := range hooks { err := hk() if err != nil { panic(err) } } if SessionOn { var err error sessionConfig := AppConfig.String("sessionConfig") if sessionConfig == "" { sessionConfig = `{"cookieName":"` + SessionName + `",` + `"gclifetime":` + strconv.FormatInt(SessionGCMaxLifetime, 10) + `,` + `"providerConfig":"` + SessionSavePath + `",` + `"secure":` + strconv.FormatBool(EnableHttpTLS) + `,` + `"sessionIDHashFunc":"` + SessionHashFunc + `",` + `"sessionIDHashKey":"` + SessionHashKey + `",` + `"enableSetCookie":` + strconv.FormatBool(SessionAutoSetCookie) + `,` + `"domain":"` + SessionDomain + `",` + `"cookieLifeTime":` + strconv.Itoa(SessionCookieLifeTime) + `}` } GlobalSessions, err = session.NewManager(SessionProvider, sessionConfig) if err != nil { panic(err) } go GlobalSessions.GC() } err := BuildTemplate(ViewsPath) if err != nil { if RunMode == "dev" { Warn(err) } } middleware.VERSION = VERSION middleware.AppName = AppName middleware.RegisterErrorHandler() if EnableDocs { Get("/docs", serverDocs) Get("/docs/*", serverDocs) } //init mime AddAPPStartHook(initMime) }
復制代碼

可以看到首先拼湊出來的是conf配置文件的路勁,如果存在然后調用ParseConfig()解析conf。

然后是

 for _, hk := range hooks { err := hk() if err != nil { panic(err) } }

hooks的定義

type hookfunc func() error //hook function to run
var hooks []hookfunc       //hook function slice to store the hookfunc func init() { hooks = make([]hookfunc, 0) }

hooks是一個hookfun的切片,

// The hookfunc will run in beego.Run() // such as sessionInit, middlerware start, buildtemplate, admin start func AddAPPStartHook(hf hookfunc) { hooks = append(hooks, hf) }

上面的代碼是在啟動的時候添加自己的方法hook。也就是hooks是在啟動之前,留給用戶初始化一些東西的時候。

復制代碼
if SessionOn { var err error sessionConfig := AppConfig.String("sessionConfig") if sessionConfig == "" { sessionConfig = `{"cookieName":"` + SessionName + `",` + `"gclifetime":` + strconv.FormatInt(SessionGCMaxLifetime, 10) + `,` + `"providerConfig":"` + SessionSavePath + `",` + `"secure":` + strconv.FormatBool(EnableHttpTLS) + `,` + `"sessionIDHashFunc":"` + SessionHashFunc + `",` + `"sessionIDHashKey":"` + SessionHashKey + `",` + `"enableSetCookie":` + strconv.FormatBool(SessionAutoSetCookie) + `,` + `"domain":"` + SessionDomain + `",` + `"cookieLifeTime":` + strconv.Itoa(SessionCookieLifeTime) + `}` } GlobalSessions, err = session.NewManager(SessionProvider, sessionConfig) if err != nil { panic(err) } go GlobalSessions.GC() } err := BuildTemplate(ViewsPath) if err != nil { if RunMode == "dev" { Warn(err) } }
復制代碼

下面就開始來解析conf文件。如果sessionConfig為空,就使用默認的json數據。然后就開始根據提供的config配置文件創建一個sessionmanager對象

這是session.NewManager()方法的實現

復制代碼
// Create new Manager with provider name and json config string. // provider name: // 1. cookie // 2. file // 3. memory // 4. redis // 5. mysql // json config: // 1. is https default false // 2. hashfunc default sha1 // 3. hashkey default beegosessionkey // 4. maxage default is none func NewManager(provideName, config string) (*Manager, error) { provider, ok := provides[provideName] if !ok { return nil, fmt.Errorf("session: unknown provide %q (forgotten import?)", provideName) } cf := new(managerConfig) cf.EnableSetCookie = true err := json.Unmarshal([]byte(config), cf) if err != nil { return nil, err } if cf.Maxlifetime == 0 { cf.Maxlifetime = cf.Gclifetime } err = provider.SessionInit(cf.Maxlifetime, cf.ProviderConfig) if err != nil { return nil, err } if cf.SessionIDHashFunc == "" { cf.SessionIDHashFunc = "sha1" } if cf.SessionIDHashKey == "" { cf.SessionIDHashKey = string(generateRandomKey(16)) } return &Manager{ provider, cf, }, nil }
復制代碼

可以推測。session.NewManager(SessionProvider,sessionConfig)中SessionProvider是一個全局變量,使用的是在config.go中默認的SessionProvider = "memory",然后改方法返回的是一個Manager的指針對象,即*Manager,所以GlobalSessions是一個*Manager對象。

然后啟動一個攜程執行GC()方法。下面是GC的源碼

// Start session gc process.
// it can do gc in times after gc lifetime. func (manager *Manager) GC() { manager.provider.SessionGC() time.AfterFunc(time.Duration(manager.config.Gclifetime)*time.Second, func() { manager.GC() }) }

所以上面的代碼是一個無限循環,每隔一段time。DUration之后執行GC().

err := BuildTemplate(ViewsPath)
    if err != nil { if RunMode == "dev" { Warn(err) } }

這里就開始編譯模板了。

復制代碼
// build all template files in a directory. // it makes beego can render any template file in view directory. func BuildTemplate(dir string) error { if _, err := os.Stat(dir); err != nil { if os.IsNotExist(err) { return nil } else { return errors.New("dir open err") } } self := &templatefile{ root: dir, files: make(map[string][]string), } err := filepath.Walk(dir, func(path string, f os.FileInfo, err error) error { return self.visit(path, f, err) }) if err != nil { fmt.Printf("filepath.Walk() returned %v\n", err) return err } for _, v := range self.files { for _, file := range v { t, err := getTemplate(self.root, file, v...) if err != nil { Trace("parse template err:", file, err) } else { BeeTemplates[file] = t } } } return nil }
復制代碼

首先判斷目錄是否存在。目錄ViewsPath在config中有初始化。然后初始化templatefile結構體,filepath.Walk()走一邊目錄里的文件,記錄在self.files里面。循環self.files中的file(map[dir][]file]),用getTemplate獲取template.Template實例,保存在beego.BeeTemplates(map[string]template.Template)。

然后是

復制代碼
middleware.VERSION = VERSION
    middleware.AppName = AppName middleware.RegisterErrorHandler() if EnableDocs { Get("/docs", serverDocs) Get("/docs/*", serverDocs) } //init mime AddAPPStartHook(initMime)
復制代碼

middleware包括的是錯誤處理的功能。如NotFound()、Forbidden()、Errorhandler()等等處理。。

隨后的AddAPPStartHook(initMine)則是初始化所有的minetype類型的函數。

上面的代碼實在beego項目啟動前需要操作的比如初始化conf配置、編譯模板文件、注冊錯誤處理中間件、加載所有的mimetype類型、

然后繼續回到beego.run()代碼中間

    if EnableAdmin { go beeAdminApp.Run() } BeeApp.Run()

很簡單。如果beego允許admin。則執行beeAdminApp。beeAdminApp也是一個*beego.adminApp,負責系統監控、性能檢測、訪問統計和健康檢查等。然后豬線程運行BeeApp.Run()方法,開始執行beego。

下面看看beego.adminApp的代碼

復制代碼
// adminApp is an http.HandlerFunc map used as beeAdminApp. type adminApp struct { routers map[string]http.HandlerFunc } // Route adds http.HandlerFunc to adminApp with url pattern. func (admin *adminApp) Route(pattern string, f http.HandlerFunc) { admin.routers[pattern] = f } // Run adminApp http server. // Its addr is defined in configuration file as adminhttpaddr and adminhttpport. func (admin *adminApp) Run() { if len(toolbox.AdminTaskList) > 0 { toolbox.StartTask() } addr := AdminHttpAddr if AdminHttpPort != 0 { addr = fmt.Sprintf("%s:%d", AdminHttpAddr, AdminHttpPort) } for p, f := range admin.routers { http.Handle(p, f) } err := http.ListenAndServe(addr, nil) if err != nil { BeeLogger.Critical("Admin ListenAndServe: ", err) } }
復制代碼
復制代碼
// task interface
type Tasker interface {
    GetStatus() string
    Run() error
    SetNext(time.Time)
    GetNext() time.Time
    SetPrev(time.Time)
    GetPrev() time.Time
}
AdminTaskList map[string]Tasker
復制代碼
復制代碼
// start all tasks
func StartTask() {
    isstart = true go run() } func run() { now := time.Now().Local() for _, t := range AdminTaskList { t.SetNext(now) } for { sortList := NewMapSorter(AdminTaskList) sortList.Sort() var effective time.Time if len(AdminTaskList) == 0 || sortList.Vals[0].GetNext().IsZero() { // If there are no entries yet, just sleep - it still handles new entries // and stop requests. effective = now.AddDate(10, 0, 0) } else { effective = sortList.Vals[0].GetNext() } select { case now = <-time.After(effective.Sub(now)): // Run every entry whose next time was this effective time. for _, e := range sortList.Vals { if e.GetNext() != effective { break } go e.Run() e.SetPrev(e.GetNext()) e.SetNext(effective) } continue case <-changed: continue case <-stop: return } } } // start all tasks func StopTask() { isstart = false stop <- true } // add task with name func AddTask(taskname string, t Tasker) { AdminTaskList[taskname] = t if isstart { changed <- true } } // add task with name func DeleteTask(taskname string) { delete(AdminTaskList, taskname) if isstart { changed <- true } }
復制代碼

adminApp結構體里面只有map結構的router,toolbox.AdminTaskList是一個map類型的結構。如果AdminTaskList中間有Tasker。則開始執行StartTask(),而且,StartTask()方法中實現的是另外打開一個協程執行Run()方法。最后打開http.ListenAndServe()實現監聽。

下面是BeeApp.Run()

復制代碼
package beego

import ( "fmt" "net" "net/http" "net/http/fcgi" "time" "github.com/astaxie/beego/context" ) // FilterFunc defines filter function type. type FilterFunc func(*context.Context) // App defines beego application with a new PatternServeMux. type App struct { Handlers *ControllerRegistor Server *http.Server } // NewApp returns a new beego application. func NewApp() *App { cr := NewControllerRegister() app := &App{Handlers: cr, Server: &http.Server{}} return app } // Run beego application. func (app *App) Run() { addr := HttpAddr if HttpPort != 0 { addr = fmt.Sprintf("%s:%d", HttpAddr, HttpPort) } BeeLogger.Info("Running on %s", addr) var ( err error l net.Listener ) endRunning := make(chan bool, 1) if UseFcgi { if HttpPort == 0 { l, err = net.Listen("unix", addr) } else { l, err = net.Listen("tcp", addr) } if err != nil { BeeLogger.Critical("Listen: ", err) } err = fcgi.Serve(l, app.Handlers) } else { app.Server.Addr = addr app.Server.Handler = app.Handlers app.Server.ReadTimeout = time.Duration(HttpServerTimeOut) * time.Second app.Server.WriteTimeout = time.Duration(HttpServerTimeOut) * time.Second if EnableHttpTLS { go func() { time.Sleep(20 * time.Microsecond) if HttpsPort != 0 { app.Server.Addr = fmt.Sprintf("%s:%d", HttpAddr, HttpsPort) } err := app.Server.ListenAndServeTLS(HttpCertFile, HttpKeyFile) if err != nil { BeeLogger.Critical("ListenAndServeTLS: ", err) time.Sleep(100 * time.Microsecond) endRunning <- true } }() } if EnableHttpListen { go func() { app.Server.Addr = addr err := app.Server.ListenAndServe() if err != nil { BeeLogger.Critical("ListenAndServe: ", err) time.Sleep(100 * time.Microsecond) endRunning <- true } }() } } <-endRunning }
復制代碼

上面的代碼首先是獲取地址addr,然后執行fast-cgi,調用ListenAndServeTLS監聽cgi服務,后面的是Http服務,調用ListenAndServe()監聽http服務。

 

復制代碼
func ListenAndServe(addr string, handler Handler) error {
    server := &Server{Addr: addr, Handler: handler} return server.ListenAndServe() } // ListenAndServe listens on the TCP network address srv.Addr and then // calls Serve to handle requests on incoming connections. If // srv.Addr is blank, ":http" is used. func (srv *Server) ListenAndServe() error { addr := srv.Addr if addr == "" { addr = ":http" } ln, err := net.Listen("tcp", addr) if err != nil { return err } return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)}) } // Serve accepts incoming connections on the Listener l, creating a // new service goroutine for each. The service goroutines read requests and // then call srv.Handler to reply to them. func (srv *Server) Serve(l net.Listener) error { defer l.Close() var tempDelay time.Duration // how long to sleep on accept failure for { rw, e := l.Accept() if e != nil { if ne, ok := e.(net.Error); ok && ne.Temporary() { if tempDelay == 0 { tempDelay = 5 * time.Millisecond } else { tempDelay *= 2 } if max := 1 * time.Second; tempDelay > max { tempDelay = max } srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay) time.Sleep(tempDelay) continue } return e } tempDelay = 0 c, err := srv.newConn(rw) if err != nil { continue } c.setState(c.rwc, StateNew) // before Serve can return go c.serve() } }
復制代碼

ListenAndServe()的功能:

1、初始化一個Server

2、調用Server的ListenAndServe()

3、調用net.Listen(“tcp”, addr)監聽端口

4、啟動一個for循環,在循環體中Accept請求

5、對每個請求實例化一個Conn,並且開啟一個goroutine為這個請求進行服務go c.serve()

下面看看進入c.serve()方法的源碼

復制代碼
// Serve a new connection.
func (c *conn) serve() { origConn := c.rwc // copy it before it's set nil on Close or Hijack  defer func() { if err := recover(); err != nil { const size = 64 << 10 buf := make([]byte, size) buf = buf[:runtime.Stack(buf, false)] c.server.logf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf) } if !c.hijacked() { c.close() c.setState(origConn, StateClosed) } }() if tlsConn, ok := c.rwc.(*tls.Conn); ok { if d := c.server.ReadTimeout; d != 0 { c.rwc.SetReadDeadline(time.Now().Add(d)) } if d := c.server.WriteTimeout; d != 0 { c.rwc.SetWriteDeadline(time.Now().Add(d)) } if err := tlsConn.Handshake(); err != nil { c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err) return } c.tlsState = new(tls.ConnectionState) *c.tlsState = tlsConn.ConnectionState() if proto := c.tlsState.NegotiatedProtocol; validNPN(proto) { if fn := c.server.TLSNextProto[proto]; fn != nil { h := initNPNRequest{tlsConn, serverHandler{c.server}} fn(c.server, tlsConn, h) } return } } for { w, err := c.readRequest() if c.lr.N != c.server.initialLimitedReaderSize() { // If we read any bytes off the wire, we're active.  c.setState(c.rwc, StateActive) } if err != nil { if err == errTooLarge { // Their HTTP client may or may not be // able to read this if we're // responding to them and hanging up // while they're still writing their // request. Undefined behavior. io.WriteString(c.rwc, "HTTP/1.1 413 Request Entity Too Large\r\n\r\n") c.closeWriteAndWait() break } else if err == io.EOF { break // Don't reply } else if neterr, ok := err.(net.Error); ok && neterr.Timeout() { break // Don't reply  } io.WriteString(c.rwc, "HTTP/1.1 400 Bad Request\r\n\r\n") break } // Expect 100 Continue support req := w.req if req.expectsContinue() { if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 { // Wrap the Body reader with one that replies on the connection req.Body = &expectContinueReader{readCloser: req.Body, resp: w} } req.Header.Del("Expect") } else if req.Header.get("Expect") != "" { w.sendExpectationFailed() break } // HTTP cannot have multiple simultaneous active requests.[*] // Until the server replies to this request, it can't read another, // so we might as well run the handler in this goroutine. // [*] Not strictly true: HTTP pipelining. We could let them all process // in parallel even if their responses need to be serialized. serverHandler{c.server}.ServeHTTP(w, w.req) if c.hijacked() { return } w.finishRequest() if w.closeAfterReply { if w.requestBodyLimitHit { c.closeWriteAndWait() } break } c.setState(c.rwc, StateIdle) } }
復制代碼

上面的代碼實現:

1、讀取每個請求的內容w, err := c.readRequest()

2、判斷handler是否為空,如果沒有設置handler(這個例子就沒有設置handler),handler就設置為DefaultServeMux

3、調用handler的ServeHttp

4、根據request選擇handler,並且進入到這個handler的ServeHTTP

5、選擇handler

 下面就開始Http請求的過程了。上文中提到的handler在beego項目中就是beego.ControllerRegistor結構體,下面是ControllerRegistor的源碼。可以看見。實現了http.handler接口的ServeHTTP方法。而且,上下文對象context也被初始化了。后面的do_filter就是實現過濾方法的實現。然后就是判斷請求的方法、seesion等函數。

而且還有一個很重要的就是runrouter、runMethod、findrouter、routerInfo這四個參數,在方法開頭就已經定義了。

復制代碼
// ControllerRegistor containers registered router rules, controller handlers and filters. type ControllerRegistor struct { routers map[string]*Tree enableFilter bool filters map[int][]*FilterRouter } // Implement http.Handler interface. func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) { defer p.recoverPanic(rw, r) starttime := time.Now() var runrouter reflect.Type var findrouter bool var runMethod string var routerInfo *controllerInfo w := &responseWriter{writer: rw} if RunMode == "dev" { w.Header().Set("Server", BeegoServerName) } // init context context := &beecontext.Context{ ResponseWriter: w, Request: r, Input: beecontext.NewInput(r), Output: beecontext.NewOutput(), } context.Output.Context = context context.Output.EnableGzip = EnableGzip // defined filter function do_filter := func(pos int) (started bool) { if p.enableFilter { if l, ok := p.filters[pos]; ok { for _, filterR := range l { if ok, p := filterR.ValidRouter(r.URL.Path); ok { context.Input.Params = p filterR.filterFunc(context) if w.started { return true } } } } } return false } // filter wrong httpmethod if _, ok := HTTPMETHOD[r.Method]; !ok { http.Error(w, "Method Not Allowed", 405) goto Admin } // filter for static file if do_filter(BeforeStatic) { goto Admin } serverStaticRouter(context) if w.started { findrouter = true goto Admin } // session init if SessionOn { context.Input.CruSession = GlobalSessions.SessionStart(w, r) defer func() { context.Input.CruSession.SessionRelease(w) }() } if r.Method != "GET" && r.Method != "HEAD" { if CopyRequestBody && !context.Input.IsUpload() { context.Input.CopyBody() } context.Input.ParseFormOrMulitForm(MaxMemory) } if do_filter(BeforeRouter) { goto Admin } if context.Input.RunController != nil && context.Input.RunMethod != "" { findrouter = true runMethod = context.Input.RunMethod runrouter = context.Input.RunController } if !findrouter { if t, ok := p.routers[r.Method]; ok { runObject, p := t.Match(r.URL.Path) if r, ok := runObject.(*controllerInfo); ok { routerInfo = r findrouter = true if splat, ok := p[":splat"]; ok { splatlist := strings.Split(splat, "/") for k, v := range splatlist { p[strconv.Itoa(k)] = v } } context.Input.Params = p } } } //if no matches to url, throw a not found exception if !findrouter { middleware.Exception("404", rw, r, "") goto Admin } if findrouter { //execute middleware filters if do_filter(BeforeExec) { goto Admin } isRunable := false if routerInfo != nil { if routerInfo.routerType == routerTypeRESTFul { if _, ok := routerInfo.methods[r.Method]; ok { isRunable = true routerInfo.runfunction(context) } else { middleware.Exception("405", rw, r, "Method Not Allowed") goto Admin } } else if routerInfo.routerType == routerTypeHandler { isRunable = true routerInfo.handler.ServeHTTP(rw, r) } else { runrouter = routerInfo.controllerType method := r.Method if r.Method == "POST" && context.Input.Query("_method") == "PUT" { method = "PUT" } if r.Method == "POST" && context.Input.Query("_method") == "DELETE" { method = "DELETE" } if m, ok := routerInfo.methods[method]; ok { runMethod = m } else if m, ok = routerInfo.methods["*"]; ok { runMethod = m } else { runMethod = method } } } // also defined runrouter & runMethod from filter if !isRunable { //Invoke the request handler vc := reflect.New(runrouter) execController, ok := vc.Interface().(ControllerInterface) if !ok { panic("controller is not ControllerInterface") } //call the controller init function execController.Init(context, runrouter.Name(), runMethod, vc.Interface()) //call prepare function execController.Prepare() //if XSRF is Enable then check cookie where there has any cookie in the request's cookie _csrf if EnableXSRF { execController.XsrfToken() if r.Method == "POST" || r.Method == "DELETE" || r.Method == "PUT" || (r.Method == "POST" && (context.Input.Query("_method") == "DELETE" || context.Input.Query("_method") == "PUT")) { execController.CheckXsrfCookie() } } execController.URLMapping() if !w.started { //exec main logic switch runMethod { case "GET": execController.Get() case "POST": execController.Post() case "DELETE": execController.Delete() case "PUT": execController.Put() case "HEAD": execController.Head() case "PATCH": execController.Patch() case "OPTIONS": execController.Options() default: if !execController.HandlerFunc(runMethod) { in := make([]reflect.Value, 0) method := vc.MethodByName(runMethod) method.Call(in) } } //render template if !w.started && context.Output.Status == 0 { if AutoRender { if err := execController.Render(); err != nil { panic(err) } } } } // finish all runrouter. release resource execController.Finish() } //execute middleware filters if do_filter(AfterExec) { goto Admin } } do_filter(FinishRouter) Admin: timeend := time.Since(starttime) //admin module record QPS if EnableAdmin { if FilterMonitorFunc(r.Method, r.URL.Path, timeend) { if runrouter != nil { go toolbox.StatisticsMap.AddStatistics(r.Method, r.URL.Path, runrouter.Name(), timeend) } else { go toolbox.StatisticsMap.AddStatistics(r.Method, r.URL.Path, "", timeend) } } } if RunMode == "dev" { var devinfo string if findrouter { if routerInfo != nil { devinfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s | % -40s |", r.Method, r.URL.Path, timeend.String(), "match", routerInfo.pattern) } else { devinfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s |", r.Method, r.URL.Path, timeend.String(), "match") } } else { devinfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s |", r.Method, r.URL.Path, timeend.String(), "notmatch") } Debug(devinfo) } // Call WriteHeader if status code has been set changed if context.Output.Status != 0 { w.writer.WriteHeader(context.Output.Status) } }
復制代碼

下面開始看看路由的調用,上面代碼中的

復制代碼
if findrouter { //execute middleware filters if do_filter(BeforeExec) { goto Admin } isRunable := false if routerInfo != nil { if routerInfo.routerType == routerTypeRESTFul { if _, ok := routerInfo.methods[r.Method]; ok { isRunable = true routerInfo.runfunction(context) } else { middleware.Exception("405", rw, r, "Method Not Allowed") goto Admin } } else if routerInfo.routerType == routerTypeHandler { isRunable = true routerInfo.handler.ServeHTTP(rw, r) } else { runrouter = routerInfo.controllerType method := r.Method if r.Method == "POST" && context.Input.Query("_method") == "PUT" { method = "PUT" } if r.Method == "POST" && context.Input.Query("_method") == "DELETE" { method = "DELETE" } if m, ok := routerInfo.methods[method]; ok { runMethod = m } else if m, ok = routerInfo.methods["*"]; ok { runMethod = m } else { runMethod = method } } }
復制代碼

首先是do_filter(BeforeExec)進入go Admin,執行控制器方法前面的過濾。然后vc := reflect.New(runrouter)創建一個控制器實例。最后在執行do_filter(AfterExec)過濾器方法。在execController.Init(context, runrouter.Name(), runMethod, vc.Interface())里面實現了初始化controller的方法。每次請求都會不相同。

最后在下面的代碼

復制代碼
if !w.started { //exec main logic switch runMethod { case "GET": execController.Get() case "POST": execController.Post() case "DELETE": execController.Delete() case "PUT": execController.Put() case "HEAD": execController.Head() case "PATCH": execController.Patch() case "OPTIONS": execController.Options() default: if !execController.HandlerFunc(runMethod) { in := make([]reflect.Value, 0) method := vc.MethodByName(runMethod) method.Call(in) } }
復制代碼

按照不同的求情方式請求不同的方法。默認的是根據反射。然后method.call()來調用。實現了router的路由注冊。。

終於寫完了。其實我也不知道自己寫的是什么。過幾天再改進。。待續。。。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM