beego项目运行过程

来源:互联网 发布:单片机大学生毕业设计 编辑:程序博客网 时间:2024/04/30 03:58

http://www.cnblogs.com/guhao123/p/4056978.html

一:首先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 runvar hooks []hookfunc       //hook function slice to store the hookfuncfunc init() {    hooks = make([]hookfunc, 0)}

hooks是一个hookfun的切片,

// The hookfunc will run in beego.Run()// such as sessionInit, middlerware start, buildtemplate, admin startfunc 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 nonefunc 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 interfacetype Tasker interface {    GetStatus() string    Run() error    SetNext(time.Time)    GetNext() time.Time    SetPrev(time.Time)    GetPrev() time.Time}AdminTaskList map[string]Tasker
复制代码
复制代码
// start all tasksfunc 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 tasksfunc StopTask() {    isstart = false    stop <- true}// add task with namefunc AddTask(taskname string, t Tasker) {    AdminTaskList[taskname] = t    if isstart {        changed <- true    }}// add task with namefunc 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 beegoimport (    "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的路由注册。。

终于写完了。其实我也不知道自己写的是什么。过几天再改进。。待续。。。。


0 0
原创粉丝点击