先从业务开发角度出发,来逐渐引出中间件。
一、刚开始时业务开发
开始业务开发时,业务需求比较少。
当我们最开始进行业务开发时,需求不是很多。 第一个需求产是品向大家打声招呼:“hello world”。
接到需求任务,我们就进行代码开发了。
一般都会写下如下的代码,用handlefunc来处理请求的服务
package main
import (
"net/http"
)
func helloHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello world"))
}
func main() {
http.HandleFunc("/", helloHandler)
http.ListenAndServe(":8080", nil)
}
假如现在业务有变化了,我们要新增一个hello服务的处理耗时,怎么做?
这个需求比较简单,修改代码如下:
package main
import (
"log"
"net/http"
"os"
"time"
)
var logger = log.New(os.Stdout, "", 0)
func helloHandler(w http.ResponseWriter, r *http.Request) {
timeStart := time.Now()
w.Write([]byte("hello world"))
timeElapsed := time.Since(timeStart)
logger.Println(timeElapsed)
}
func main() {
http.HandleFunc("/", helloHandler)
http.ListenAndServe(":8080", nil)
}
这样就可以输出当前hello请求到日志文件了。
完成了这个需求后。过了没多久,又有新的需求来了,我们要显示信息,显示Email,
显示好朋友,并且这就一个接口也需要增加耗时记录。
一下子又增加了很多api, 简略示例代码如下:
package main
func helloHandler(wr http.ResponseWriter, r *http.Request) {
// ...
}
func showInfoHandler(wr http.ResponseWriter, r *http.Request) {
// ...
}
func showEmailHandler(wr http.ResponseWriter, r *http.Request) {
// ...
}
func showFriendsHandler(wr http.ResponseWriter, r *http.Request) {
timeStart := time.Now()
wr.Write([]byte("your friends is tom and alex"))
timeElapsed := time.Since(timeStart)
logger.Println(timeElapsed)
}
func main() {
http.HandleFunc("/", helloHandler)
http.HandleFunc("/info/show", showInfoHandler)
http.HandleFunc("/email/show", showEmailHandler)
http.HandleFunc("/friends/show", showFriendsHandler)
// ...
}
每一个handler里面都需要记录运行的时间,每次新加路由都要写同样的代码。都要把业务逻辑代码拷贝过来。
业务继续发展,又有了新的需求,增加一个监控系统,需要你上报接口运行时间到监控系统里面,以便监控接口的稳定性。这个监控系统叫metrics。
好了,现在你又要修改代码,通过http post方式把耗时时间发送给metrics系统。
而且你要修改好多个handler,增加metrics上报接口代码。
修改代码:
func helloHandler(wr http.ResponseWriter, r *http.Request) {
timeStart := time.Now()
wr.Write([]byte("hello"))
timeElapsed := time.Since(timeStart)
logger.Println(timeElapsed)
// 新增耗时上报
metrics.Upload("timeHandler", timeElapsed)
}