大话 Iris
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 协议》,转载必须注明作者和本文链接