Golang 依赖注入

1. 手动实现依赖注入

package main

import "fmt"

type A struct {
	B *B
}

type B struct {
	Inject string
}

func main() {
	var a A
	b := B{Inject: "Golang"}
	fmt.Println(b.Inject)
	a.B = &b
	fmt.Println(a.B.Inject)
}

2.开源的依赖注入框架

  1. 依赖反射实现的运行时的依赖注入(facebook/inject、uber/dig)
  2. 使用代码生成实现的依赖注入(google/wire)

facebookgo/inject :

facebookgo/inject 实现依赖注入: 类A的实例a是需要被注入的对象,类B的实例b是依赖的组件 将a、b的依赖关系交给第三方(IOC容器)来控制,调用Provide我们不再需要编写复杂的依赖代码(各种参数,实例的互相传入)。执行完Populate后,我们就可以直接使用实例a,其中需要依赖的组件在运行时由IOC容器来注入。

package main

import (
	"fmt"
	"net/http"
	"os"

	"github.com/facebookgo/inject"
)

// Our Awesome Application renders a message using two APIs in our fake
// world.
type HomePlanetRenderApp struct {
	// The tags below indicate to the inject library that these fields are
	// eligible for injection. They do not specify any options, and will
	// result in a singleton instance created for each of the APIs.

	NameAPI   *NameAPI   `inject:""`
	PlanetAPI *PlanetAPI `inject:""`
}

func (a *HomePlanetRenderApp) Render(id uint64) string {
	return fmt.Sprintf(
		"%s is from the planet %s.",
		a.NameAPI.Name(id),
		a.PlanetAPI.Planet(id),
	)
}

// Our fake Name API.
type NameAPI struct {
	// Here and below in PlanetAPI we add the tag to an interface value.
	// This value cannot automatically be created (by definition) and
	// hence must be explicitly provided to the graph.

	HTTPTransport http.RoundTripper `inject:""`
}

func (n *NameAPI) Name(id uint64) string {
	// in the real world we would use f.HTTPTransport and fetch the name
	return "Spock"
}

// Our fake Planet API.
type PlanetAPI struct {
	HTTPTransport http.RoundTripper `inject:""`
}

func (p *PlanetAPI) Planet(id uint64) string {
	// in the real world we would use f.HTTPTransport and fetch the planet
	return "Vulcan"
}

func main() {
	// Typically an application will have exactly one object graph, and
	// you will create it and use it within a main function:
	var g inject.Graph

	// We provide our graph two "seed" objects, one our empty
	// HomePlanetRenderApp instance which we're hoping to get filled out,
	// and second our DefaultTransport to satisfy our HTTPTransport
	// dependency. We have to provide the DefaultTransport because the
	// dependency is defined in terms of the http.RoundTripper interface,
	// and since it is an interface the library cannot create an instance
	// for it. Instead it will use the given DefaultTransport to satisfy
	// the dependency since it implements the interface:
	var a HomePlanetRenderApp
	err := g.Provide(
		&inject.Object{Value: &a},
		&inject.Object{Value: http.DefaultTransport},
	)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	// Here the Populate call is creating instances of NameAPI &
	// PlanetAPI, and setting the HTTPTransport on both to the
	// http.DefaultTransport provided above:
	if err := g.Populate(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	// There is a shorthand API for the simple case which combines the
	// three calls above is available as inject.Populate:
	//
	//   inject.Populate(&a, http.DefaultTransport)
	//
	// The above API shows the underlying API which also allows the use of
	// named instances for more complex scenarios.

	fmt.Println(a.Render(42))

}
Output:

Spock is from the planet Vulcan.

uber/dig:

my.ini

app_name = web

# possible values: DEBUG, INFO, WARNING, ERROR, FATAL
log_level = DEBUG

[mysql]
ip = 127.0.0.1
port = 3306
user = dj
password = 123456
database = awesome

[redis]
ip = 127.0.0.1
port = 6379
db = 0
package main

import (
	"fmt"

	"github.com/jessevdk/go-flags"
	"go.uber.org/dig"
	"gopkg.in/ini.v1"
)

type Option struct {
	ConfigFile string `short:"c" long:"config" description:"Name of config file."`
}

func InitOption() (*Option, error) {
	var opt Option
	_, err := flags.Parse(&opt)

	return &opt, err
}

func InitConf(opt *Option) (*ini.File, error) {
	cfg, err := ini.Load(opt.ConfigFile)
	return cfg, err
}

func PrintInfo(cfg *ini.File) {
	fmt.Println("App Name:", cfg.Section("").Key("app_name").String())
	fmt.Println("Log Level:", cfg.Section("").Key("log_level").String())
}

func main() {
	container := dig.New()

	container.Provide(InitOption)
	container.Provide(InitConf)

	container.Invoke(PrintInfo)
}

Golang 依赖注入_第1张图片

你可能感兴趣的:(Golang,golang,di)