必须显式注册所有依赖类型和控制器,否则运行时 panic;注册需用指针形式(如(*userrepo)(nil)),接口实现、构造函数、作用域(singleton/request)均需明确指定,且必须在 app.listen() 前完成。

必须先注册类型,否则运行时 panic;控制器字段注入依赖前,app.Register 和 app.RegisterController 两步缺一不可。
所有依赖类型必须显式注册,不能靠字段标签自动推导
字段上的 inject:"" 标签只是触发注入的开关,Iris 不会扫描代码去“发现”类型。容器启动时找不到对应注册项,调用控制器方法瞬间就 panic。
- 注册接口实现时,传
(*UserRepo)(nil),不是UserRepo{}—— 否则反射无法识别其是否实现了UserRepository - 注册构造函数比注册实例更安全,尤其涉及资源(如 DB 连接):
app.Register(func() *sql.DB { return dbConn }) - 若注册了
*UserService,但控制器字段是UserService(值类型),注入失败——类型必须完全一致
控制器本身也要注册,且必须传类型而非实例
app.RegisterController[UserController]() 是必须调用的一步。它告诉容器:“这个结构体将来会被实例化并注入依赖”,而不是把一个现成的对象塞进去。
- 错误写法:
app.RegisterController(&UserController{})—— 容器会忽略,后续字段注入全为 nil - 控制器内嵌
iris.Controller不影响注册逻辑,但字段注入仍依赖上述注册动作 - 若控制器方法签名含
iris.Context参数(比如Get(ctx iris.Context)),上下文会自动注入,不需额外注册
生命周期控制要靠注册选项,不是靠字段标签
字段标签 inject:"" 只管“要不要注入”,不管“怎么创建”。单例、每次请求新建、还是按上下文作用域,全由 app.Register 的参数决定。
- 默认是 Singleton:
app.Register(NewLogger)→ 全局唯一实例 - 想每次 HTTP 请求新建:用
iris.ScopeRequest或app.Scoped,且工厂函数必须接收iris.Context参数:app.Scoped[Logger](func(ctx iris.Context) *Logger { return NewLogger(ctx) }) -
app.Singleton和app.Transient是快捷方式,但底层仍是调用app.Register+ 对应选项
常见 panic 场景和定位方法
panic 信息通常是 reflect: Call using zero Value 或 no dependency found for type *xxx,说明某处漏注册了。
- 检查 panic 堆栈最上层是否指向某个控制器方法 —— 那就是注入失败的入口点
- 确认该控制器里所有带
inject:""的字段类型,是否都已在app.Register中出现过 - 如果字段类型是接口,再确认其实现类型是否注册,且注册时用了指针形式(
(*Impl)(nil)) - 注意:MVC 注册顺序无关紧要,但必须在
app.Listen()之前完成全部Register调用
最容易被忽略的是注册时的类型精度:*sql.DB 和 sql.DB 是两个完全不同的类型,哪怕字段只差一个 *,容器也认为是未注册项。











