Martini 框架

Martini核心部分Injector

Injector模块总体构造

injector对象:
  1. type injector struct {
  2. values map[reflect.Type]reflect.Value // 保存<类型,值>对
  3. parent Injector
  4. }

TypeMaper接口
  1. type TypeMapper interface {
  2. Map(interface{}) TypeMapper // 类型映射
  3. MapTo(interface{}, interface{}) TypeMapper //将值映射为指定的类型
  4. Set(reflect.Type, reflect.Value) TypeMapper // 设置类型值
  5. Get(reflect.Type) reflect.Value
  6. }

Injectorde主体是一个Injecotr接口,Injector接口组合了Application,Invoker,以及TypeMaper接口。核心函数Invoker,通过传入一个interface,进行后续的处理。interface的具体类型必须为函数,否则会panic。通过reflect进行反射获取interface的具体函数类型。
  1. func (inj *injector) Invoke(f interface{}) ([]reflect.Value, error) {
  2. t := reflect.TypeOf(f)
  3. var in = make([]reflect.Value, t.NumIn()) //如果传入的interface不是函数,则panic
  4. for i := 0; i < t.NumIn(); i++ {
  5. argType := t.In(i)
  6. val := inj.Get(argType) // 通过函数参数类型获取函数值,injector注册器通过map保存<类型,值>对。
  7. if !val.IsValid() {
  8. return nil, fmt.Errorf("Value not found for type %v", argType)
  9. }
  10. in[i] = val
  11. }
  12. return reflect.ValueOf(f).Call(in), nil
  13. }
injector使用例子:
  1. package main
  2. import (
  3. "fmt"
  4. "github.com/codegangsta/inject"
  5. )
  6. type myString interface{}
  7. func test1(st string, myst myString) {
  8. fmt.Println(st, myst)
  9. }
  10. var (
  11. st1 = "hello"
  12. st2 = "WORLD"
  13.     myst myString =="haha"
  14. )
  15. func main() {
  16. inj := inject.New() \\生成injector实例
  17. inj.Map(st1) \\ st1注册为默认的类型
  18. inj.MapTo(st2, (*myString)(nil))\\ st2注册为指定的myStrig类型
  19. inj.Invoke(test1) \\ 函数test1通过参数了类型获取参数具体的值
  20.     fmt.Println(inject.InterfaceOf(&myst)) // myst必须为指向interface的指针,否则panic。 }
  21. }
输出:

martini服务模块

Martini结构:

使用Matrini框架时,可以自己直接使用框架内置的classicMartini。使用方法:
  1. package main
  2. import (
  3. "github.com/go-martini/martini"
  4. "fmt"
  5. "reflect"
  6. )
  7. func test1(st string) string {
  8. return st
  9. }
  10. func test2(num int) int {
  11. fmt.Println(num)
  12. return num
  13. }
  14. type INT interface{}
  15. func test3(num INT, st string) string {
  16. st = st + fmt.Sprint(reflect.TypeOf(num))
  17. return st
  18. }
  19. func main() {
  20. m := martini.Classic() //生成martini实例
  21. m.Get("/hello", test2, test1)// 注册路由
  22. m.Get("/hi", test3)
  23. m.Map("a") // 注册函数参数值
  24. m.Map(1)
  25. m.MapTo("HI", (*INT)(nil))
  26. m.Run() //启动监听服务
  27. }
工作流程:

1.使用Classic生成martini实例:
  1. func Classic() *ClassicMartini {
  2. r := NewRouter()
  3. m := New() //生成martini实例
  4. m.Use(Logger()) //注册Handler,实际是往martini.handlers里append一个Handler
  5. m.Use(Recovery())
  6. m.Use(Static("public"))
  7. m.MapTo(r, (*Routes)(nil))
  8. m.Action(r.Handle) // 注册路由处理函数,m.action=r.Handler
  9. return &ClassicMartini{m, r}
  10. }
2.注册路由函数
路由器实现:

Router接口:
  1. type Router interface {
  2. Routes
  3. // Group adds a group where related routes can be added.
  4. Group(string, func(Router), ...Handler)
  5. // Get adds a route for a HTTP GET request to the specified matching pattern.
  6. Get(string, ...Handler) Route
  7. // Patch adds a route for a HTTP PATCH request to the specified matching pattern.
  8. Patch(string, ...Handler) Route
  9. // Post adds a route for a HTTP POST request to the specified matching pattern.
  10. Post(string, ...Handler) Route
  11. // Put adds a route for a HTTP PUT request to the specified matching pattern.
  12. Put(string, ...Handler) Route
  13. // Delete adds a route for a HTTP DELETE request to the specified matching pattern.
  14. Delete(string, ...Handler) Route
  15. // Options adds a route for a HTTP OPTIONS request to the specified matching pattern.
  16. Options(string, ...Handler) Route
  17. // Head adds a route for a HTTP HEAD request to the specified matching pattern.
  18. Head(string, ...Handler) Route
  19. // Any adds a route for any HTTP method request to the specified matching pattern.
  20. Any(string, ...Handler) Route
  21. // AddRoute adds a route for a given HTTP method request to the specified matching pattern.
  22. AddRoute(string, string, ...Handler) Route
  23. // NotFound sets the handlers that are called when a no route matches a request. Throws a basic 404 by default.
  24. NotFound(...Handler)
  25. // Handle is the entry point for routing. This is used as a martini.Handler
  26. Handle(http.ResponseWriter, *http.Request, Context)
  27. }
例子中使用Get注册路由,Martini中注册路由与其他框架不同的地方在于,路由的函数可以是任意类型,而且同一个路劲可以注册多个处理函数。
注册路由时,实际内部都是使用router.addroute()
  1. func (r *router) addRoute(method string, pattern string, handlers []Handler) *route {
  2. if len(r.groups) > 0 {
  3. groupPattern := ""
  4. h := make([]Handler, 0)
  5. for _, g := range r.groups {
  6. groupPattern += g.pattern
  7. h = append(h, g.handlers...)
  8. }
  9. pattern = groupPattern + pattern
  10. h = append(h, handlers...) //将注册的方法append进handlers ,请求路劲到此路由的时候会遍历调用该handlers,直到函数有返回值
  11. handlers = h
  12. }
  13. fmt.Println("handlers:", reflect.ValueOf(handlers))
  14. route := newRoute(method, pattern, handlers) // 生成指定路径方法的路由
  15. fmt.Println("route:", reflect.ValueOf(route.handlers))
  16. route.Validate()
  17. r.appendRoute(route)
  18. return route
  19. }
addRoute生成一个route并添加进router.routes。当客户端请求时,遍历改routes获取对应路由。
addRoute方法调用了newRoute返回一个*route
route结构
  1. type route struct {
  2. method string
  3. regex *regexp.Regexp
  4. handlers []Handler
  5. pattern string
  6. name string
  7. }
newRoute将注册的方法添加进handlers。
例子中的m.Get("/hello", test2, test1)及将test1,test2这两个函数添加去route.handlers.
当请求路径为/hello时,就会调用这两个方法。
3.map为函数参数注入参数值
4.run启动服务器监听请求
  1. func (m *Martini) ServeHTTP(res http.ResponseWriter, req *http.Request) {
  2. //res.Write([]byte("hello"))
  3. m.createContext(res, req).run()
  4. }
ServerHTTP是每一个request请求实例的入口。
对于每一个req实例,createContext生成一个上下文。
  1. func (m *Martini) createContext(res http.ResponseWriter, req *http.Request) *context {
  2. c := &context{inject.New(), m.handlers, m.action, NewResponseWriter(res), 0} //生成context实例
  3. c.SetParent(m)
  4. c.MapTo(c, (*Context)(nil)) //注入请求参数值
  5. c.MapTo(c.rw, (*http.ResponseWriter)(nil))
  6. c.Map(req)
  7. return c
  8. }
run进行路由处理。
  1. func (c *context) run() {
  2. for c.index <= len(c.handlers) { // 遍历handlers,handlers实际为例子中使用USE注册的logger,recovery。当左右相等时,则调用m.action,及路由处理器
  3. _, err := c.Invoke(c.handler())
  4. if err != nil {
  5. panic(err)
  6. }
  7. c.index += 1 // 计数器,用来遍历注册的路由器
  8. if c.Written() {
  9. return
  10. }
  11. }
  12. }
run首先调用第一个注册的Logger。
  1. func Logger() Handler {
  2. return func(res http.ResponseWriter, req *http.Request, c Context, log *log.Logger) {
  3. start := time.Now()
  4. addr := req.Header.Get("X-Real-IP")
  5. if addr == "" {
  6. addr = req.Header.Get("X-Forwarded-For")
  7. if addr == "" {
  8. addr = req.RemoteAddr
  9. }
  10. }
  11. log.Printf("Started %s %s for %s", req.Method, req.URL.Path, addr)
  12. rw := res.(ResponseWriter)
  13. c.Next() //调用第二个注册的recovery
  14. log.Printf("Completed %v %s in %v\n", rw.Status(), http.StatusText(rw.Status()), time.Since(start))
  15. }
  16. }
Martini一个神奇的地方在于Next这个函数,log,recovery记忆Handle通过next实现嵌套调用。
其次调用Recovery
  1. func Recovery() Handler {
  2. return func(c Context, log *log.Logger) {
  3. defer func() { // 捕获路由处理panic
  4. if err := recover(); err != nil {
  5. stack := stack(3)
  6. log.Printf("PANIC: %s\n%s", err, stack)
  7. // Lookup the current responsewriter
  8. val := c.Get(inject.InterfaceOf((*http.ResponseWriter)(nil)))
  9. res := val.Interface().(http.ResponseWriter)
  10. // respond with panic message while in development mode
  11. var body []byte
  12. if Env == Dev {
  13. res.Header().Set("Content-Type", "text/html")
  14. body = []byte(fmt.Sprintf(panicHtml, err, err, stack))
  15. } else {
  16. body = []byte("500 Internal Server Error")
  17. }
  18. res.WriteHeader(http.StatusInternalServerError)
  19. if nil != body {
  20. res.Write(body)
  21. }
  22. }
  23. }()
  24. c.Next() // 调用Handle进行请求路由处理
  25. }
  26. }
router.Handle路由处理
  1. func (r *router) Handle(res http.ResponseWriter, req *http.Request, context Context) {
  2. fmt.Println(reflect.TypeOf(r.getRoutes()))
  3. bestMatch := NoMatch
  4. var bestVals map[string]string
  5. var bestRoute *route
  6. for _, route := range r.getRoutes() {
  7. match, vals := route.Match(req.Method, req.URL.Path)
  8. fmt.Println(match, vals)
  9. if match.BetterThan(bestMatch) {
  10. bestMatch = match // 遍历查找匹配的路径路由
  11. bestVals = vals
  12. bestRoute = route
  13. if match == ExactMatch {
  14. break
  15. }
  16. }
  17. }
  18. if bestMatch != NoMatch {
  19. fmt.Println("bestvals", bestVals)
  20. params := Params(bestVals)
  21. context.Map(params)
  22. bestRoute.Handle(context, res) // 路由器逻辑处理
  23. return
  24. }
  25. // no routes exist, 404
  26. c := &routeContext{context, 0, r.notFounds} //没有匹配路由时,执行默认的处理函数。notfind在初始化时注册
  27. context.MapTo(c, (*Context)(nil))
  28. c.run()
  29. }
路由业务逻辑处理route.Handle
  1. func (r *route) Handle(c Context, res http.ResponseWriter) {
  2. context := &routeContext{c, 0, r.handlers} // 初始化context,例子中对于/hello路径的请求r.handlers =[test2,test1]
  3. c.MapTo(context, (*Context)(nil))
  4. c.MapTo(r, (*Route)(nil))
  5. context.run() // 路由业务逻辑处理,遍历r.handlers获取业务逻辑方法
  6. }
run业务逻辑处理
  1. func (r *routeContext) run() {
  2. for r.index < len(r.handlers) {// 遍历handlers,实际实现时可以重写这一方法,自定义要调用方法的顺序。通过设置index可以自定义调用
  3. handler := r.handlers[r.index]
  4. vals, err := r.Invoke(handler)
  5. if err != nil {
  6. panic(err)
  7. }
  8. r.index += 1
  9. // if the handler returned something, write it to the http response
  10. //如果r.handlers的函数有返回值,则把返回值写入resp并设置r.writern()的返回值为true
  11. if len(vals) > 0 {
  12. ev := r.Get(reflect.TypeOf(ReturnHandler(nil)))
  13. handleReturn := ev.Interface().(ReturnHandler)
  14. handleReturn(r, vals)
  15. }
  16. if r.Written() {
  17. return
  18. }
  19. }
  20. }


实际使用Martini框架时,也可以根据需要自定义重写martini结果。重写martini结构后续的流程处理也是类似的。




posted @ 2015-09-29 13:46  林堂辉  阅读(910)  评论(0编辑  收藏  举报