SoFunction
Updated on 2025-03-04

The specific use of Go dependency injection tool wire

Go is relatively newer languages ​​than java and C++, but it also has many excellent features and ecological libraries. This article introduces the commonly used functions in most software engineering: dependency injection. First, let’s introduce what dependency injection is, and the differences between Go implementation library Wire and other languages. Then, dependency injection is implemented through simple examples to simplify the code and improve readability.

Dependency injection

Dependency injection is a technique in which an object receives other objects (called dependencies) on which it depends. Typically, the receiving object is called a client, and the incoming ("injected") object is called a service.

For a better understanding, the following is a simple example:

package main
import (
   "fmt"
)
type Message string
type Greeter struct {
   Message Message
}
type Event struct {
   Greeter Greeter
}
func GetMessage() Message {
   return Message("Hello world!")
}
func GetGreeter(m Message) Greeter {
   return Greeter{Message: m}
}
func (g Greeter) Greet() Message {
   return 
}
func GetEvent(g Greeter) Event {
   return Event{Greeter: g}
}
func (e Event) Start() {
   msg := ()
   (msg)
}
func main() {
   message := GetMessage()
   greeter := GetGreeter(message)
   event := GetEvent(greeter)
   ()
}

The above code includes message, greeter, event; GetMessage function returns a message, GetGreeter function accepts a message and returns a greeter, getEvent function accepts a greeter and returns an event. There is also a method to start the output message for the event.

In the main function, a message is first created, then passed into greeter as a dependency, and finally to the event. Running the program can see the output "Hello world!", which is a relatively shallow dependency graph, but it can also see its complexity, which is also the value of the dependency injection library wire.

Introduction to Wire

Wire is a code dependency tool. It does not adopt a reflection mechanism or runtime state. Using Wire can effectively avoid manual hard code dependencies. Wire generates source code at compile time, official documentation describes: "In Wire, dependencies between components are represented as function parameters, encouraging explicit initialization instead of global variables." (In Wire, dependencies between components are represented as function parameters, and explicit initialization is preferred over global variables.)

Install wire through the following command:go get /google/wire/cmd/wire; Install wire globally to generate code for subsequent use of wire commands:go install /google/wire/cmd/wire

Next, we use Wire as a dependency injection tool to refactor the above code, add new files, and add the following code:

//go:build wireinject
// +build wireinject
package main
import "/google/wire"
func InitializeEvent() Event {
   (GetMessage, GetGreeter, GetEvent)
   return Event{}
}

First import wire, and then create the InitializeEvent function, which returns the event called in the main function. Wire is called in the function body, and all dependencies are passed in the builder method. Note that the order is not related to the passing dependencies. Then return the empty event, no need to worry, all handed over to Wire.

Note that the comments on the file tell Go to ignore the file when compiling, and make sure that one empty line is added after the comment line.

The following is the main function code:

func main() {
   event := InitializeEvent()
   ()
}

Now I successfully downgraded the main function code to two lines. In the code directory, execute the wire command, and wire will generate the wire_gen.go file:

// Code generated by Wire. DO NOT EDIT.
//go:generate go run /google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject
package main
// Injectors from :
func InitializeEvent() Event {
    message := GetMessage()
    greeter := GetGreeter(message)
    event := GetEvent(greeter)
    return event
}

The same generated files have more comments than the files! , means that wire is ignored at compile time and starts at compile time. This is the correct output result for running the main function.

With parameter dependency

What if dynamic incoming messages are required as parameters? Let's modify the GetMessage function:

func GetMessage(text string) Message {
   return Message(text)
}

Run the wire command again and you can see that the wire_gen.go code has also been modified accordingly:

// Code generated by Wire. DO NOT EDIT.
//go:generate go run /google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject
package main
// Injectors from :
func InitializeEvent(text string) Event {
    message := GetMessage(text)
    greeter := GetGreeter(message)
    event := GetEvent(greeter)
    return event
}

Now modify the code:

func main() {
    event := InitializeEvent("Hello Golang")
    ()
}

The operation results are consistent with expectations.

If you modify the code, the simulation lacks some dependencies:

func InitializeEvent(text string) Event {
    (GetMessage, GetEvent)
    return Event{}
}

Execute the wire command and it will correctly prompt that the corresponding dependencies are missing:

inject InitializeEvent: no provider found for needed by in provider "GetEvent" 

Summarize

This article introduces the basic wire concept and introduces dynamic implementation of dependency injection through simple examples. However, wire will generally be used in larger projects. For more advanced functions, please refer to the official documentation:/google/wire/blob/main/docs/#advanced-features

This is the end of this article about Go dependency injection tool wire. For more related content about Go dependency injection tool wire, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!