一、函数包装
现在有一个简单的 HTTP 服务器,监听并接受来自客户端的请求。
1
2
3
4
5
6
7
8
9
|
func main() {
server := http.Server{Addr: "127.0.0.1:8080"}
http.HandleFunc("/hello", hello)
server.ListenAndServe()
}
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hello world")
}
|
我们现在需要监控 hello
函数处理请求的用时,应该如何操作呢?
我们很容易就能想到在hello
函数中添加一个计时器,然后打印出函数执行的时间。
但这样需要我们直接修改hello
函数的内容,有没有一种非入侵式的办法呢?
我们可以在原函数外面再包装一层函数,在新函数中去实现计时的逻辑,需要用到 函数作为参数 和 函数作为返回值。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
func main() {
server := http.Server{Addr: "127.0.0.1:8080"}
http.HandleFunc("/hello", timed(hello))
server.ListenAndServe()
}
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hello world")
}
func timed(f func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
f(w, r)
end := time.Now()
fmt.Println("请求耗时:", end.Sub(start))
}
}
|
这样,每发送一次HTTP请求,就会调用一次timed
函数,输出请求耗时。
这种方式称为函数包装(Function Wrapping)或函数装饰(Function Decoration),通过包装函数,可以在不修改原始函数的情况下增加额外的功能,比如计时、日志记录等。