概述
Fx是一个golang版本的依赖注入框架,在项目中的引用:
import "github.com/uber-go/fx"
Fx用途
Fx应用程序,使用依赖注入来消除全局变量,而无需手动将函数连接在一起。
同时,go.uber.org/fx/fxtest也为Fx应用程序提供了端到端测试的能力。
Fx应用
func NewHandler(logger *log.Logger) (http.Handler, error) {
logger.Print("Executing NewHandler.")
return http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
logger.Print("Got a request.")
}), nil
}
func NewMux(lc fx.Lifecycle, logger *log.Logger) *http.ServeMux {
logger.Print("Executing NewMux.")
mux := http.NewServeMux()
server := &http.Server{
Addr: ":8080",
Handler: mux,
}
// 这里,NewMux通过传入fx.Lifecycle,用来执行启动和结束的Hook函数
// 注意Hook函数的类型是固定的: func(context.Context) error
lc.Append(fx.Hook{
// 在fx.start的hook中,将http的server启动起来
OnStart: func(context.Context) error {
logger.Print("Starting HTTP server.")
go server.ListenAndServe()
return nil
},
// 在fx.stop的Hook中,将http的server停止
OnStop: func(ctx context.Context) error {
logger.Print("Stopping HTTP server.")
return server.Shutdown(ctx)
},
})
return mux
}
// Register用于注册http server的路由,注册handle是传入的
// 这样就可以被fx框架给连接起来
func Register(mux *http.ServeMux, h http.Handler) {
mux.Handle("/", h)
}
func main() {
app := fx.New(
// Provide 所有我们需要的构造函数, 告诉 Fx 我们想要如何去构造
// 此时并不会执行注册的构造函数
fx.Provide(
NewLogger,
NewHandler,
NewMux,
),
// 下面的Invoke会立刻执行,执行下面函数时,如果需要参数,那么会根据入参类型在Provide中登记的函数的返回值来匹配
// 将匹配到的函数作为入参传入invoke需要执行的函数。这个过程是递归的
fx.Invoke(Register),
// 这部分是可选的. 使用下面的代码, 你可以控制Fx在哪logs5它的事件
fx.WithLogger(
func() fxevent.Logger {
return fxevent.NopLogger
},
),
)
// In a typical application, we could just use app.Run() here. Since we
// don't want this example to run forever, we'll use the more-explicit Start
// and Stop.
// 这里执行fx的start,是为了执行登记通过fx.Lifecycle.Append登记的start Hook
// 此时会执行前面登记的是启动 http server
startCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
if err := app.Start(startCtx); err != nil {
log.Fatal(err)
}
// Normally, we'd block here with <-app.Done(). Instead, we'll make an HTTP
// request to demonstrate证明 that our server is running.
if _, err := http.Get("http://localhost:8080/"); err != nil {
log.Fatal(err)
}
stopCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
if err := app.Stop(stopCtx); err != nil {
log.Fatal(err)
}
}
Output:
Executing NewLogger.
Executing NewMux.
Executing NewHandler.
Starting HTTP server.
Got a request.
Stopping HTTP server.