一:首先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的路由注册。。
终于写完了。其实我也不知道自己写的是什么。过几天再改进。。待续。。。。