Service层应放在项目根目录下./services,命名统一为复数形式services,内部文件按业务域命名如user_service.go;结构体需显式声明依赖字段(如repo、log),并通过BeforeActivation手动注册注入,方法须返回error而非panic或HTTP响应。

Service层该放在哪个目录、叫什么名
按 Iris 官方 MVC 习惯和社区主流实践,service 目录应与 controllers、models 并列,放在项目根目录下(如 ./services),不要嵌套进 controllers 或混在 main.go 里。名字统一用复数形式 services,内部文件按业务域命名,比如 user_service.go、order_service.go —— 这不是强制约定,但能避免团队成员反复猜“service 是单数还是小写 Service”。
Service结构体要不要带依赖字段
要,而且必须显式声明。Iris 的 MVC controller 不会自动注入 service 实例,得靠 BeforeActivation 手动注册并赋值。常见错误是直接在 controller 里 new(UserService),结果每次请求都新建实例,无法共享连接池或缓存。
- 在
user_service.go中定义结构体时,把依赖(如 repository、logger、cache)作为字段声明:type UserService struct { repo UserRepository; log *zap.Logger } - 在 controller 的
BeforeActivation中,用b.Register()注入已初始化的实例:b.Register(&UserService{repo: userRepo, log: app.Logger()}) - controller 结构体里对应字段类型要匹配:
Service *UserService,Iris 会自动绑定
Service方法返回 error 还是 panic
Service 层本身不处理 HTTP 状态码,只负责纯业务逻辑和错误分类。它应该返回 error,而不是自己 panic 或调用 ctx.JSON —— 那是 controller 的事。否则就破坏了分层职责,导致 service 无法被 CLI 工具、定时任务或其他非 HTTP 场景复用。
- 正确:
func (s *UserService) FindByID(id int64) (*User, error) { ... } - 错误:
func (s *UserService) FindByID(id int64) { if id - 错误还体现在:service 方法里出现
iris.Context参数,这说明它已经越界承担了 controller 职责
多个Service之间怎么复用逻辑
别复制粘贴,用依赖注入解耦。比如订单模块需要用户权限校验,不要在 OrderService 里重写一遍用户查询和角色判断逻辑,而是把它抽成独立的 AuthService,然后让 OrderService 也依赖它。
- 在
auth_service.go中封装通用校验:func (a *AuthService) CanAccessUser(ctx iris.Context, userID int64) bool - 在
OrderController.BeforeActivation中同时注册AuthService和OrderService -
OrderService的构造函数接收*AuthService字段,调用其方法即可
这种模式下,新增一个支付模块要用同样校验,只需再注入一次 AuthService,不用动已有代码。容易被忽略的是:所有被 b.Register() 注入的实例,在同一个 MVC 应用生命周期内是单例,所以务必确保它们是并发安全的。


















