Put a piece of code first
package mainimport ( "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) }}
Here, listen to the local 9090 port, using HTTP. Handlefunc a request with a URL of "/" to the method named Hello. This is a more common golang simple web implementation, but it would be very strange to look at, it is recommended to run the code first, and then we will look at the source of the handler definition first.
type Handler interface { ServeHTTP(ResponseWriter, *Request)}
As shown in the code, handler is actually an interface that implements the Servehttp (Responsewriter, *request) function, which is equivalent to implementing a handler. Popular speaking handler is the function of processing input and output stream, registering handler to the router, the equivalent of binding a specific URL to this function, when the client requests access to the URL, the router will use this function to operate.
There may be children's shoes will be questioned, hello this function is not a handler, why you can register a URL as handler. This is because there is a function called Handlefunc, here is the principle of handlefunc. First list the source code:
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { DefaultServeMux.HandleFunc(pattern, handler)}
Handlefunc Pass in a string (URL) and a func (Responsewriter, request ), hello this function is compliant with func (Responsewriter, request), Then use Defaultservemux for processing, what is Defaultservemux? The definition of Defaultservemux can be easily found in the source code of Server.go.
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 = &defaultServeMuxvar defaultServeMux ServeMux
From the source can know Defaultservemux equivalent to a public route, a public variable, URL and handle is registered to this route. It is important to note that the SERVEMUX member variable has a sync. Rwmutex, know Golang concurrency should know, this is a read-write lock (mutiple Read,single write lock, read single write lock, allows multiple read operations to execute in parallel, but the write operation is completely mutually exclusive, when the read operation is more frequent than sync. Mutex has better performance), this should also be considered as a Web server, read operations will be more frequent. Next look at the MUX. Handle (Pattern, Handlerfunc (handler)) to which step you should see a function Handlerfunc (handler):
type HandlerFunc func(ResponseWriter, *Request)// ServeHTTP calls f(w, r).func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { f(w, r)}
See here you should understand why hello this function does not implement the handler method is also a handler, because handlerfunc the Hello Force implementation servehttp (W Responsewriter, R *request), So hello this function is also a handler.
This is the last step of the route.
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 }}
The public variable Defaultservemux registers the handler, where a read-write lock is used and a private structure muxentry, where the routing registration is over.