依赖注入 fx

概述

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.

参考

  1. fx Godoc
  2. golang fx 依赖注入包学习笔记


blog comments powered by Disqus
—  原创作品许可 — 署名-非商业性使用-禁止演绎 3.0 未本地化版本 — CC BY-NC-ND 3.0   —