iris 不内置依赖注入,需手动构造并传递依赖。controller 必须通过带参构造函数创建,在 main() 中显式传入依赖实例,否则字段为 nil 导致 panic;handler 依赖推荐用闭包捕获,di 工具如 wire 仅生成 wiring 代码,不与 iris 生命周期集成。

依赖注入不是 Iris 内置功能,得自己手写 wiring
Iris 本身不提供 IoC 容器或自动依赖解析——它没有 app.Register()、app.Resolve() 这类方法。所谓“Iris 支持依赖注入”,实际是指它允许你把依赖作为参数传给 Controller 构造函数,但创建和组装过程完全由你控制。
常见错误是翻文档看到 mvc.Application 或 Controller 字段标注了 inject 标签,就以为框架会自动扫描注入。不会。Iris 不解析 struct tag,也不管理对象生命周期。
- 所有依赖必须在
func main()中显式构造、传递 - Controller 实例必须手动 new 并传给
mvc.New().Handle() - 如果你用
new(MyController)而没传依赖,字段就是零值(nil指针、空接口),运行时 panic - 别指望
iris.Context或app实例能当容器用——它们不保存你注册的服务
Controller 构造函数注入要自己 new,不能靠框架实例化
想让 MyController 拿到数据库连接或日志器,就得定义带参构造函数,并在 main() 里调用它:
type MyController struct {
DB *sql.DB
Log *zerolog.Logger
}
func NewMyController(db *sql.DB, log *zerolog.Logger) *MyController {
return &MyController{DB: db, Log: log}
}
func main() {
app := iris.New()
db := setupDB() // 自己开连接
log := setupLogger()
mvcApp := mvc.New(app.Party("/api"))
mvcApp.Handle(NewMyController(db, log)) // ← 必须手动传,不能用 new(MyController)
app.Listen(":8080")
}
如果漏掉这一步,直接 mvcApp.Handle(new(MyController)),那 DB 和 Log 字段都是 nil,后续调用 c.DB.QueryRow() 就 panic。
-
mvc.New().Handle()只负责把实例绑定到路由,不做任何初始化或依赖填充 - 字段注入(如
db *sql.DB `inject:"db"`)在 Iris 中无效,属于误读文档或混淆其他框架 - 若 Controller 有多个依赖,建议封装成 config struct 传入,避免构造函数参数爆炸
中间件和 Handler 的依赖只能靠闭包或全局变量传
Iris 的 iris.Handler 签名固定为 func(iris.Context),没法直接塞依赖。所以数据库、缓存等服务只能通过以下方式透传:
- 闭包捕获:用匿名函数包裹 handler,把依赖作为外部变量引用
- 全局变量:不推荐,破坏可测试性,且并发不安全
- Context 值存储:用
ctx.Values().Set("db", db)+ctx.Values().Get("db"),但类型断言易出错,且绕过编译检查
推荐闭包方式,清晰可控:
func userHandler(db *sql.DB) iris.Handler {
return func(ctx iris.Context) {
id := ctx.Params().GetInt64Default("id", 0)
var name string
db.QueryRow("SELECT name FROM users WHERE id = ?", id).Scan(&name)
ctx.JSON(iris.Map{"name": name})
}
}
func main() {
app := iris.New()
db := setupDB()
app.Get("/user/{id:int}", userHandler(db)) // ← 依赖提前绑定
app.Listen(":8080")
}
别试图用第三方 DI 库和 Iris 强耦合
像 Wire、Dig 这类 Go DI 工具,本质是生成 func main() 的 wiring 代码。它们可以和 Iris 共存,但不能“集成”进 Iris 生命周期——Iris 不暴露钩子、不回调你的工厂函数。
容易踩的坑:
- 在 Wire 的
injector函数里调mvc.New().Handle(),结果发现 Controller 构造时机不可控,依赖还没 ready 就被调用了 - 把
app当作容器注册服务,比如app.RegisterValue("logger", log),Iris 没这个 API,编译失败 - 误以为
app.ConfigureContainer()存在(这是 Echo 或 Gin 插件的命名习惯,Iris 没有)
真正可行的做法只有一种:用 Wire/Dig 生成一个返回 *MyController 的函数,在 main() 里调它,再传给 mvc.Handle()。整个链路仍是线性的、显式的。
最常被忽略的一点:Controller 的依赖如果含状态(比如带连接池的 DB、带缓冲区的 logger),务必确认它们是线程安全的——Iris 的 Context 是复用的,但 Controller 实例是单例,它的字段会被并发请求共享。











