gf框架之服務註冊 – 框架核心元件,比你以為的更強大

gf框架之服務註冊 – 框架核心元件,比你以為的更強大

文章來源:http://gf.johng.cn/494368

當使用者訪問某個URI時,Web Server能夠精確的呼叫特定的服務介面提供服務,這些都是通過“服務註冊”來實現的。Web Server提供服務需要回撥函式/方法/物件/控制器的支援,ghttp包支援多種服務註冊模式,為開發者提供非常強大和靈活的介面功能。服務註冊是整個Web Server最核心的部分,也是gf框架中最精心設計的一個模組。本章節將會進行詳細介紹。

服務註冊管理由ghttp包提供,API文件地址:godoc.org/github.com/johng-cn/gf

服務註冊介紹

本章開始之前,我們再來看一下本手冊開頭的Hello World程式:

package main

import "gitee.com/johng/gf/g/net/ghttp"

func main() {
    ghttp.GetServer().BindHandler("/", func(r *ghttp.Request) {
        r.Response.Write("哈嘍世界!")
    })
}

其中,使用BindHandler

其中BindController*

其中HttpMethod(支援的Method:GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE

各項引數說明和Server的對應方法一致,只不過在Domain物件的底層會自動將方法繫結到Domain指定的域名列表中,只有對應的域名才能提供訪問。

我們來看一個簡單的例子,我們將前面的Hello World程式改成如下形式:

package main

import "gitee.com/johng/gf/g/net/ghttp"

func init() {
    ghttp.GetServer().Domain("localhost").BindHandler("/", func(r *ghttp.Request) {
        r.Response.Write("Hello World!")
    })
}

我們再次使用 http://127.0.0.1/ 進行訪問,發現Web Server返回404,為什麼呢?因為該程式中的回撥函式只註冊到了localhost域名中,其他域名自然無法訪問。當然,前面也提到Domain方法的域名引數支援多個,自定義域名的服務註冊相當方便。

服務註冊初始化

所有的服務註冊統一在包的init初始化方法中完成(init是Go語言內建的包初始化方法,並且一個包中支援多個init方法),一個包可以包含多個檔案,每個檔案都可以有一個init初始化方法,可以分開註冊,在使用的時候會通過同一個包引入程序序,自動呼叫初始化方法完成註冊。可以參考示例檔案。

來看一個例子:

gitee.com/johng/gf/blob/master/geg/frame/mvc/main.go

package main

import (
    "gitee.com/johng/gf/g/net/ghttp"
    _ "gitee.com/johng/gf/geg/frame/mvc/controller/demo"
)

func main() {
    ghttp.GetServer().SetPort(8199)
    ghttp.GetServer().Run()
}

其中通過:

import _ "gitee.com/johng/gf/geg/frame/mvc/controller/demo"

這樣一條類似於all in one的語句便完成了對包中的所有控制器的引入和註冊(當然,包中的init應當實現註冊方法呼叫),在demo包中包含了多個控制器、執行物件、回撥函式的註冊,demo包具體的控制器註冊以及相關邏輯我們將在後續章節繼續介紹。

控制器註冊

控制器註冊

這種方式將每一個請求都當做一個控制器物件來處理,比較類似且媲美於PHP的請求執行模式,當一個請求進來之後,立即初始化一個新的控制器物件進行處理,處理完成之後釋放控制器資源。這種服務註冊方式的優點是簡單、安全、OOP設計,每個請求的控制器嚴格資料隔離,成員變數無法相互共享。

我們可以通過ghttp.BindController

服務註冊必須提供註冊的URI,註冊時ghttp會將所有控制器的公開方法將會對映到指定URI末尾,具體參見示例程式碼說明。註冊的控制器引數是一個ghttp.Controller

啟動外層的main.go,我們嘗試著訪問http://127.0.0.1:8199/method/info

Init與Shut回撥方法

ghttp.Controller

gmvc.Controller基類

type Controller struct {
    Request  *ghttp.Request  // 請求資料物件
    Response *ghttp.Response // 返回資料物件(r.Response)
    Server   *ghttp.Server   // Web Server物件(r.Server)
    Cookie   *ghttp.Cookie   // COOKIE操作物件
    Session  *ghttp.Session  // SESSION操作物件
    View     *View           // 檢視物件
}

Init回撥方法
控制器初始化方法,引數是當前請求的物件。gmvc.Controller

可以看到,執行物件在進行服務註冊時便生成了一個物件(執行物件在Web Server啟動時便生成),此後不管多少請求進入,Web Server都是將請求轉交給該物件對應的方法進行處理。需要注意的是,公開方法的定義與控制器註冊不同,必須為以下形式:

func(r *ghttp.Request) 

否則無法完成註冊,呼叫註冊方法時會有錯誤提示,形如:

panic: interface conversion: interface {} is xxx, not func(*ghttp.Request)

該示例執行後可以通過,通過http://127.0.0.1:8199/object/show

這個例子比較簡單,並且也演示了域名繫結執行物件方法的操作。ObjectMethod物件的
http://127.0.0.1:8199/object-method/show1

回撥函式註冊

這種方式的執行機制類似於執行物件註冊,不過註冊的是一個函式/方法。相比較於執行物件註冊,註冊時不會有額外的物件例項化開銷,註冊時只是儲存了一個函式/方法的指標地址。這種方式的服務註冊比較靈活,註冊的服務可以是一個例項化物件的方法地址,也可以是一個包方法地址。服務需要的資料可以通過包內部變數形式或者物件內部變數形式進行管理,開發者可根據實際情況進行靈活控制。

我們可以通過ghttp.BindHandler

事件回撥註冊

ghttp.Server提供了事件回撥註冊功能,支援使用者對於某一事件進行自定義監聽處理,按照URI pattern方式進行繫結註冊。支援多個方法對同一事件進行監聽,ghttp.Server將會按照註冊順序進行回撥方法呼叫。
相關方法如下:

func (s *Server) BindHookHandler(pattern string, hook string, handler HandlerFunc) error
func (s *Server) BindHookHandlerByMap(pattern string, hookmap map[string]HandlerFunc) error

當然域名物件也支援事件回撥註冊:

func (d *Domain) BindHookHandler(pattern string, hook string, handler HandlerFunc) error
func (d *Domain) BindHookHandlerByMap(pattern string, hookmap map[string]HandlerFunc) error

支援的事件列表:

BeforeServe

當訪問http://127.0.0.1:8199/時,執行Web Server程序的終端將會按照事件的執行流程列印出對應的事件名稱。