模块与依赖注入
VEF 基于 Uber FX 构建。公开的 vef 包把最常用的 FX helper 重新导出了,所以大多数应用都可以在同一套 API 表面内完成组合。
核心思路
你不需要手动启动每个子系统,而是通过 FX option 组合它们:
vef.Run(
user.Module,
auth.Module,
vef.ProvideAPIResource(resources.NewHealthResource),
)
在内部,vef.Run(...) 会把你的 option 追加到框架自己的模块列表里,再启动整个 FX 应用。
在真实项目中,main.go 常常更像这样:
vef.Run(
ivef.Module, // 框架侧集成
mcp.Module, // 自定义 MCP provider
web.Module, // SPA 托管
auth.Module, // 认证加载器
sys.Module, // 系统/管理资源
md.Module, // 主数据资源
pmr.Module, // 业务资源
)
这反映出一个重要模式:VEF 应用通常是由多块小模块组合出来的,而不是一个超大的总模块。
vef 重新导出的常用 helper
业务侧最常接触的是这些:
vef.Runvef.Modulevef.Providevef.Supplyvef.Invokevef.Decoratevef.Replace
这样大多数应用代码不需要频繁直接 import fx。
基于 group 的扩展点
很多框架能力都是通过 FX group 串起来的。对应用开发者最重要的是:
vef:api:resourcesvef:app:middlewaresvef:cqrs:behaviorsvef:security:challenge_providersvef:mcp:toolsvef:mcp:resourcesvef:mcp:templatesvef:mcp:prompts
di.go 里的各种 helper,本质上就是帮你更安全地把值注册进这些 group。
API 资源注册
最常用的 helper 是:
vef.ProvideAPIResource(NewUserResource)
它会把构造函数结果打上 API resource group 标签。启动时,API 模块会从这个 group 收集所有资源,并把其中的操作注册进引擎。
其他 provider 也是同一个模式
中间件、CQRS、登录挑战、MCP 也都一样:
vef.ProvideMiddleware(NewAuditTrailMiddleware)
vef.ProvideCQRSBehavior(NewTracingBehavior)
vef.ProvideChallengeProvider(NewTOTPChallengeProvider)
vef.ProvideMCPTools(NewToolProvider)
这些 helper 的价值不在“增加新能力”,而在于把 FX group tag 隐藏掉,让应用代码更易读。
大型应用里的模块角色
在更接近生产的 VEF 项目里,通常会出现这些固定角色:
internal/vef:build info、共享框架侧 service、事件订阅器internal/auth:UserLoader、UserInfoLoader、认证相关初始化- 若干业务域模块:注册 API 资源
- 可选的
web和mcp模块:分别负责 SPA 与 MCP 集成
这样职责会比“一个 app 模块包所有东西”清楚得多。
用 vef.Invoke(...) 做集成型模块
在规模更大的应用里,经常会有一个专门的集成模块,通过 vef.Invoke(...) 做启动期 wiring,而不是直接暴露业务资源。
例如:
var Module = vef.Module(
"app:vef",
vef.Supply(BuildInfo),
vef.Provide(NewDataDictLoader, password.NewBcryptEncoder),
vef.Invoke(registerEventSubscribers),
)
这种模块很适合放 build info、共享框架侧 service,以及事件订阅器注册。
为什么资源能自动发现
API engine 不要求你手动挂路由。它会按下面的流程工作:
- 从容器里收集资源
- 从资源本身和嵌入的 CRUD provider 里收集操作
- 解析 handler
- 把 handler 适配成 Fiber handler
- 挂载到 RPC 或 REST router
所以 VEF 的典型开发方式更像“定义资源 + 注册构造函数”,而不是“声明 router + 绑定 handler + 手挂中间件”。
什么时候直接用 fx
大多数应用都可以只用 vef 包装层,但如果你需要这些高级能力,直接用 fx 也完全没问题:
- 更复杂的注解
- 可选依赖
- 直接操作 lifecycle hook
- 测试环境替换实现
VEF 并没有限制你使用 FX,它只是把最常见路径做短了。
下一步
继续看 应用生命周期,理解 vef.Run(...) 从启动到监听端口到底做了什么。