golang: dependency injection library - Wire

What is Dependency Injection

Dependency Injection (DI for short) is a software design pattern and one of the techniques for implementing Inversion of Control. This pattern allows an object to receive other objects it depends on. "Dependencies" refer to objects that are required by the receiver. "Injection" refers to the process of passing "dependencies" to the receiver. After "injection", the receiver will call the "dependency". This pattern ensures that any object that wants to use a given service does not need to know how to set up those services. Instead, external code (the injector) that connects to the receiving object (such as the client) does not know it exists to provide the services required by the receiving party.

Dependency injection involves four concepts:

  • Service: Any class that provides useful functionality.
  • Client: The class that consumes the service.
  • Interface: Clients should not know the details of service implementation, only need to know the name and API of the service
  • Injector: Injector, also known as assembler, container, provider or factory. Responsible for introducing services to customers.

Dependency injection separates object construction from object injection. Therefore, the new keyword for creating objects can also disappear.

There are two types of dependency injection frameworks for Golang:

  • Dependency injection at runtime through reflection, a typical representative is Uber's open source dig;
  • Generate code through generate, a typical representative is Google's open source wire.

Using dig will be more powerful, but the disadvantage is that errors can only be found at runtime, which may lead to some hidden bugs if you are not careful. The disadvantage of using wire is that there are more functional restrictions, but the advantage is that problems can be found when compiling, and the generated code is actually not much different from our own handwritten related code, which is more intuitive and less mentally burdensome, so wire is more recommended .

what is wire

Wire is an injection dependency code generation tool for go language that is open sourced by google. It can generate corresponding dependency injection go code according to your code.

Unlike other dependency injection tools, such as Uber's Dig and Facebook's Inject, both of these tools use reflection to implement dependency injection, and they are runtime dependency injection.

Wire is a dependency injection that generates code when compiling code, and is a compile-time dependency injection that injects dependency code during compilation. Moreover, during code generation, if there is a problem with dependency injection, an error will occur when generating the dependent code, and the problem can be reported instead of having to wait until the code is running to expose the problem.

Providers and Injectors

First, you need to understand two core concepts of wire: provider and injector

The steps of dependency injection are as follows:

  • First: need to create an instance of new
  • Second: "inject" the new class instance into the class that needs to use it through the constructor or other methods
  • Third: Use this new instance in the class.

From the above steps to understand the two core concepts of wire: provider and injector

  • The provider is equivalent to the above new class instance
  • Inject is equivalent to aggregating the required dependent functions before the "injection" action, and generating dependencies based on the aggregated functions.

Provider: Provide an object
injector: Responsible for generating new programs based on object dependencies.

provider:

Provider is an ordinary go function, which can be understood as an object constructor. Provides "artifacts" for generating the Injector function below.

The following NewUserStore() function can be seen as a provider. This function needs to pass in *Config and *mysql.DB 2 parameters.

// NewUserStore 是一个 provider for *UserStore,*UserStore 依赖 *Config,*mysql.DB
func NewUserStore(cfg *Config, db *mysql.DB) (*UserStore, error) {
    
    ... ...}

// NewDefaultConfig 是一个 provider for *Config,没有任何依赖
func NewDefaultConfig() *Config {
    
    ...}

// NewDB 是 *mysql.DB 的一个 provider ,依赖于数据库连接信息 *ConnectionInfo
func NewDB(info *ConnectionInfo) (*mysql.DB, error){
    
    ...}

Providers can be combined into a set of provider sets. This is useful for providers that are often used together. They can be combined using the wire.NewSet method

var SuperSet = wire.NewSet(NewUserStore, NewDefaultConfig)

You can also add other provider sets to a provider set

import (
    “example.com/some/other/pkg”
)

// ... ...
var MegaSet = wire.NewSet(SuperSet, pkg.OtherSet)

wire.NewSet() function:
This function can combine related providers together and use them. Of course, it can also be used alone, such as var Provider = wire.NewSet(NewDB).
The return value of this NewSet function can also be used as a parameter of other NewSet functions, such as the above SuperSet used as a parameter.

Injector

We write a program to combine these providers (such as the initUserStore() function in the following example), and the wire command in wire will call the providers in the order of dependencies to generate a more complete function, which is the injector.

First, write the signature function that generates the injector, and then use the wire command to generate the corresponding function.

Examples are as follows:

// +build wireinject

func initUserStore(info *ConnectionInfo) (*UserStore, error) {
    
    
    wire.Build(SuperSet, NewDB) // 声明获取 UserStore 需要调用哪些 provider 函数
    return nil, nil
}

Then use the wire command to generate the injector function from the above initUserStore function, and the generated function corresponds to the file name wire_gen.go.

wire 命令:
You can generate the injector by invoking Wire in the package directory。
直接在生成 injector 函数的包下,使用 wire 命令,就可以生成 injector 代码。

wire.Build() 函数:

它的参数可以是 wire.NewSet() 组织的一个或多个 provider,也可以直接使用 provider。

Join hands with Kratos

Use the following command to install Wire's command-line tool in the global path for code generation.

go install github.com/google/wire/cmd/wire@latest

scene code

Here, we make a "user service".

According to Kratos' official recommended Layout, we divide the service into the following layers: server, service, biz, data.

Guess you like

Origin blog.csdn.net/zhizhengguan/article/details/130138048