2.Golang的Http源碼閱讀(Handler註冊)

先貼一段代碼服務器

package main

import (
    "net/http"
    "fmt"
    "log"
)

func hello(w http.ResponseWriter, r *http.Request)  {
    r.ParseForm()
    fmt.Printf("%+v\n", *r.URL)
    fmt.Fprintln(w, "Hello world")
}

func main() {
    http.HandleFunc("/", hello)
    err := http.ListenAndServe(":9090", nil)
    if err != nil {
        log.Fatal(err)
    }
}

這裏監聽本地的9090端口,使用 http.HandleFunc 將URL爲「/」的請求將其轉向名爲hello的方法。這是比較常見的Golang的簡單Web的實現,可是看着會以爲很奇怪,建議先把代碼跑起來,而後咱們再來看看源碼中Handler的定義先。併發

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

如代碼中所示,Handler實際上一個接口,實現了 ServeHTTP(ResponseWriter, *Request) 這個函數,就至關於實現了一個Handler。通俗講Handler就是處理輸入輸出流的函數,將Handler註冊到路由器,等同於將特定的URL跟這個函數綁定起來,當客戶端請求訪問這個URL,路由器就會使用這個函數進行操做。
可能會有童鞋會疑問,hello這個函數並非一個Handler,爲何能夠做爲Handler註冊一個URL。這是由於這裏有一個函數叫作HandleFunc,這裏就講講HandleFunc的原理吧。先把源碼列出來:函數

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    DefaultServeMux.HandleFunc(pattern, handler)
}

HandleFunc傳入一個字符串(URL)和一個func(ResponseWriter, Request),hello這個函數是符合func(ResponseWriter, Request)的要求的,而後使用DefaultServeMux進行處理,DefaultServeMux又是什麼?在server.go的源碼中能夠輕鬆找到DefaultServeMux的定義性能

type ServeMux struct {
    mu    sync.RWMutex
    m     map[string]muxEntry
    hosts bool // whether any patterns contain hostnames
}
....
// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = &defaultServeMux

var defaultServeMux ServeMux

由源碼能夠知道DefaultServeMux至關於一個公共的路由,一個公有變量,URL和Handle就是註冊到這個路由上的。須要注意的是ServeMux的成員變量,有一個sync.RWMutex,瞭解過Golang併發的應該知道,這是一個讀寫鎖(Mutiple read,single write lock, 多讀單寫鎖,容許多個讀操做並行執行,但寫操做會徹底互斥,在讀取操做比較頻繁時比sync.Mutex有着更好的性能表現),這應該也是考慮到做爲Web服務器,讀取操做會比較頻繁。接下來看mux.Handle(pattern, HandlerFunc(handler))去到哪一步,應該看到這裏有一個函數HandlerFunc(handler):code

type HandlerFunc func(ResponseWriter, *Request)

// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)
}

看到這裏你就應該明白,爲何hello這個函數沒有實現Handler方法也是一個Handler,由於HandlerFunc把hello強制實現ServeHTTP(w ResponseWriter, r *Request),因此hello這個函數也就是一個Handler。orm

這裏是路由的最後一步了server

type muxEntry struct {
    h       Handler
    pattern string
}

// Handle registers the handler for the given pattern.
// If a handler already exists for pattern, Handle panics.
func (mux *ServeMux) Handle(pattern string, handler Handler) {
    mux.mu.Lock()
    defer mux.mu.Unlock()

    if pattern == "" {
        panic("http: invalid pattern")
    }
    if handler == nil {
        panic("http: nil handler")
    }
    if _, exist := mux.m[pattern]; exist {
        panic("http: multiple registrations for " + pattern)
    }

    if mux.m == nil {
        mux.m = make(map[string]muxEntry)
    }
    mux.m[pattern] = muxEntry{h: handler, pattern: pattern}

    if pattern[0] != '/' {
        mux.hosts = true
    }
}

公有變量DefaultServeMux將Handler註冊,這裏就用到了讀寫鎖以及一個私有結構muxEntry,到這裏,路由註冊就結束了。接口

相關文章
相關標籤/搜索