Go 目前並不支援動態生成結構體型別這類超程式設計API,因此無法如Java的Spring那樣透過註解或xml配置,“動態”生成代理類型別,更不要說 laravel 這種強依賴 ioc 容器控制反轉。但基於反射,它還是可以做到部分依賴注入,比如 路徑引數型別注入,基於函式型別配置的延遲繫結....。在Iris框架的MVC應用中,控制器的依賴是透過自動複製傳遞給“子類”
自動路由
Golang標準庫net\http
是web網路程式設計的底層支柱。如同所有web程式設計,handler 接受一個請求,返回一個響應。Iris框架的mvc則更多的是圍繞路由來做文章。iris中的控制器本質是一個持有特定字尾的結構體,該結構體持有iris特定的字首或字尾方法,以便在透過反射生成對應的HTTP謂詞Handler。這種情況,與java標準介面一致,get,post之類打頭,與早期版本laravel寫法一樣。當然也支援定義路由,及相關的類初始與結束方法。
依賴管理
在spring中可用註解或xml,甚至是java程式碼配置,來規則化物件的建立及管理。Iris框架中的物件,建立與管理需要手動維護。比如,像在laravel這種高度依賴容器的框架中,需要某個功能服務,通常註冊服務提供者,後從ioc容器中拿出來用。但在Iris中物件與物件之間,依賴的維護,物件建立關係,通常是程式碼顯性呈現。最初的例項建立,並不適合一 New了之。Irish搞了一些動態繫結,要麼將接收器作為函式的第一引數,要麼自帶隱式依賴複製。所以也就不難奇怪,有許多configurator 引數配置都是一個個持有app例項的函式變數,本質上還是在建立的物件例項變更狀態。當然所這一切,都是監聽之前完成。
函式 vs 方法
純函式暫且不論,那些會產生副作用的函式,往往是某個結構體的方法的變種。這是因為對於接收引數為引用型別的函式而言,在其內部是有機會改變外部引用物件的狀態,或執行它的方法。這種特性與語言無關,只不過在Go這種面向介面的程式語言iris框架中被放大了。
class A {...}
a = new A
a.name = "pardon110"
// 在iris中做法通常這樣
type A struct{...}
app = &A{....}
func configurator(a *A){
a.port = "8080"
}
// 後其配置
app.configure(configurator...)
看起來,點麻煩,實際上這種繫結的操作行為,就有更多的可變性,況且在Go中函式還是一等公民。
控制器
package main
import (
"github.com/kataras/iris"
"github.com/kataras/iris/middleware/logger"
"github.com/kataras/iris/middleware/recover"
"github.com/kataras/iris/mvc"
)
func main() {
app := newApp()
app.Run(iris.Addr(":8080"))
}
func newApp() *iris.Application {
app := iris.New()
// 可選的 或選的handler
app.Use(recover.New())
app.Use(logger.New())
mvc.New(app).Handle(new(ExampleController))
return app
}
// ExampleController /
type ExampleController struct{}
// Get serves
// Method: GET
// Resource: http://localhost:8080
func (c *ExampleController) Get() mvc.Result {
return mvc.Response{
ContentType: "text/html",
Text: "<h1>Welcome</h1>",
}
}
// GetPing serves
// Method: GET
// Resource: http://localhost:8080/ping
func (c *ExampleController) GetPing() string {
return "pong"
}
// GetHello serves
// Method: GET
// Resource: http://localhost:8080/hello
func (c *ExampleController) GetHello() interface{} {
return map[string]string{"message": "Hello Iris!"}
}
// BeforeActivation 一次性呼叫,在主程執行之前
// v9版本之後 可在該方法內對控制器方法指定自定義的路由
// 也可用 `b.Router` 訪問不帶MVC的標準 router
// 還可給控制器欄位 或 方法的輸入引數 增加依賴
func (c *ExampleController) BeforeActivation(b mvc.BeforeActivation) {
anyMiddlewareHere := func(ctx iris.Context) {
ctx.Application().Logger().Warnf("內部自定義 /cutstom_path")
ctx.Next()
}
// 自定義路由,無需遵守命名規則
b.Handle("GET", "/custom_path", "CustomHandlerWithoutFollowingTheNamingGuide", anyMiddlewareHere)
// 或新增該控制器的全域性中介軟體 比如使用根 /
// b.Router().Use(myMiidleware)
}
// CustomHandlerWithoutFollowingTheNamingGuide serves
// Method: GET
// Resource: http://localhost:8080/custom_path
func (c *ExampleController) CustomHandlerWithoutFollowingTheNamingGuide() string {
return "hello from the custom handler without following the naming guide"
}
// GetUserBy serves
// Method: GET
// Resource: http://localhost:8080/user/{username:string}
// By 關鍵字告知框架 路徑引數繫結
//
func (c *ExampleController) GetUserBy(username string) mvc.Result {
return mvc.View{
Name: "user/username.html",
Data: username,
}
}
/* 工廠方法將HTTP謂詞正確繫結到對應路由
func (c *ExampleController) Post() {}
func (c *ExampleController) Put() {}
func (c *ExampleController) Delete() {}
func (c *ExampleController) Connect() {}
func (c *ExampleController) Head() {}
func (c *ExampleController) Patch() {}
func (c *ExampleController) Options() {}
func (c *ExampleController) Trace() {}
*/
/*
func (c *ExampleController) All() {}
// OR
func (c *ExampleController) Any() {}
*/
// AfterActivation 所有依賴被配置完畢,但仍可新增標準handler
func (c *ExampleController) AfterActivation(a mvc.AfterActivation) {}
本作品採用《CC 協議》,轉載必須註明作者和本文連結