Iris依赖注入是严格显式的运行时机制,需提前注册完全匹配的指针类型,字段名大小写与注册类型一致,接口需注册具体实现,生命周期由Register方式决定。

Iris 的依赖注入不是“配个标签就自动生效”的魔法,它是一套严格、显式、运行时检查的绑定机制。漏注册、类型不匹配、顺序错乱,全都会在第一个请求进控制器时 panic,而不是编译报错。
字段注入必须用可导出指针,且类型完全一致
Iris 只识别首字母大写的可导出字段,并且只注入指针类型——值类型(如 UserService)或小写字段(如 db *sql.DB)一律忽略。
- ✅ 正确:
DB *sql.DB、Logger *zap.Logger、Service *UserService - ❌ 错误:
db *sql.DB(不可导出)、DB sql.DB(非指针)、DB *gorm.DB(但注册的是*sql.DB) - 字段名大小写必须和注册类型名完全一致,
Service和service是两个类型
所有依赖必须在 app.RegisterController 前注册完毕
控制器本身和它用到的所有字段类型,都得提前注册。顺序错了,容器根本不知道该往哪塞东西。
- 先注册服务:
app.Singleton[*sql.DB](func() *sql.DB { return dbConn }) - 再注册控制器:
mvc.New(app.Party("/api")).RegisterController[UserController]() - ❌ 错误:把
RegisterController写在Singleton之前 → 运行时报no dependency found for type *sql.DB - ❌ 错误:用
app.RegisterController(&UserController{})传实例 → 字段不会被注入,全为nil
接口不能直接注入,必须注册具体实现
Iris 不支持按接口类型查找实现,它只认你 Register 进去的那个具体类型。哪怕字段声明是接口,注册也得是具体指针。
- 假设你有接口
type UserRepository interface{...}和实现type UserRepo struct{...} - 注册必须写:
app.Register((*UserRepo)(nil), func() *UserRepo { return &UserRepo{} }) - 控制器字段写成:
Repo *UserRepo(不是Repo UserRepository) - 如果字段写成
Repo UserRepository,即使注册了*UserRepo,注入也会失败
生命周期由注册方式决定,和字段标签无关
inject:"" 标签只是开关,告诉 Iris “这个字段要注入”,不控制创建时机。单例还是每次请求新建,全看你怎么调用 Register。
- 全局单例:
app.Singleton[*sql.DB](newDB)或app.Register(newDB)(默认就是 Singleton) - 每次请求新建:
app.Scoped[Logger](func(ctx iris.Context) *Logger { return NewLogger(ctx) }) - Scoped 函数必须接收
iris.Context参数,否则无法绑定请求作用域 - 别指望靠字段加
inject:"request"来切换生命周期——Iris 不解析这种语义
最常被跳过的一步,是确认控制器字段类型和 Register 传入的类型是否字节级一致:带不带 *、包路径是否完全相同、有没有拼错字母。一旦不一致,panic 不会提示“类型不匹配”,只会报 reflect: Call using zero Value——你得顺着堆栈往上翻,找到 panic 发生在哪个控制器方法里,再逐个核对那个方法里所有带 inject:"" 的字段。


















