Home > Article > Backend Development > What is go language dependency injection?
In the Go language, dependency injection (DI) is a design pattern that decouples dependencies between components; when needed, different components can obtain information from other components through a unified interface. objects and states. The benefit of dependency injection is decoupling; and decoupling can bring more benefits: enhanced code scalability, enhanced code maintainability, easier unit testing, etc.
The operating environment of this tutorial: Windows 7 system, GO version 1.18, Dell G3 computer.
When I first heard this word, I was confused and it was hard to pronounce. Maybe many students who have studied spring think this is very basic and easy to understand knowledge, but Because I have never learned Java or spring before, I was very confused when I first came into contact with this term.
Dependency injection, the English name is dependency injection, or DI for short. The word dependency is easy to understand. In software design, there are large and small dependencies from architectural modules to function methods.
For example, new B needs to be created before new A. A depends on B. At this time, we can say that B is a dependency of A. A controls B. There is a coupling relationship between AB, and the code design The idea is that it is best to achieve loose coupling. If B needs to be transformed one day, then A will also need to be transformed. You may be fine with this being a dependency, but if there is a series of dependencies between A->B->C->D->E->F, then it will be very troublesome to transform.
At this time, something is needed to decouple the strong coupling between them. How to decouple it? We can only use third-party forces. We put A to B This idea of handing over control to a third party is called Inversion of Control (IOC Inversion Of Control), and this third party is called an IOC container. What the IOC container has to do is to create a new B, and then inject this instance of B into A. Then A can normally use the method based on B. This process is called dependency injection, and based on IOC This method is called dependency injection.
Simply put, dependency injection (DI) is a design pattern that decouples dependencies between components. When needed, different components can obtain objects and states in other components through a unified interface. The interface design of Go language avoids many situations where third-party dependency injection frameworks need to be used (such as Java, etc.). Our injection solution only provides very few injection solutions similar to those in Dager or Guice, and focuses on avoiding manual configuration of dependencies between objects and components.
If you understand the idea of dependency injection, you should also understand the biggest benefit it brings - decoupling .
And decoupling can bring more benefits: enhanced code scalability, enhanced code maintainability, easier unit testing, etc.
So how to implement dependency injection?
There are the following methods in Java:
Setter method injection: implement the public set method of specific properties to allow the external container to call the object of the dependent type .
Interface-based injection: Implement a specific interface for external containers to inject objects of dependent types.
Constructor-based injection: implement a constructor with specific parameters, and pass in the object of the dependent type when creating a new object.
Annotation-based injection: Add specific keywords to the code to achieve injection.
Annotations are the most common way. Like comments, they are not executed as code, but are specifically for others to read. But the readers of annotations are entirely humans, and the main readers of annotations, in addition to humans, are frameworks or precompilers.
wire is an annotation-based dependency injection method. wire
is a dependency injection tool open sourced by Google. We only need to tell wire
the dependencies between types in a special go
file, and it will automatically Help us generate code, help us create objects of specified types, and assemble its dependencies.
wire
has two basic concepts, Provider
(constructor) and Injector
(injector).
Let wire
know how to generate these dependent objects by providing the provider
function. wire
According to the injector
function signature we defined, the complete injector
function is generated. The injector
function is the final function we need. It will Call provider
in dependency order. The requirements of
wire
are very simple. Create a new wire.go
file (the file name can be arbitrary) and create our initialization function. For example, if we want to create and initialize a Mission
object, we can do this:
//+build wireinject package main import "github.com/google/wire" func InitMission(name string) Mission { wire.Build(NewMonster, NewPlayer, NewMission) return Mission{} }
You can see the annotation on the first line: build wireinject, indicating that this is an injector. build
is actually a feature of the Go language. Similar to C/C conditional compilation, some options can be passed in when executing go build
, and based on these options it is decided whether certain files are compiled. The wire
tool will only process files with wireinject
, so our wire.go
file must add this.
In the function, we call wire.Build()
to pass in the constructor of the type that Mission
depends on. For example, you need to call NewMission()
to create the Mission
type. NewMission()
accepts two parameters, one of Monster
type and one of Player
type. Monster
type objects need to be created by calling NewMonster()
, and Player
type objects need to be created by calling NewPlayer()
. So NewMonster()
and NewPlayer()
we also need to pass to wire
.
After writing the wire.go file and executing the wire command, a wire_gen.go file will be automatically generated.
// Code generated by Wire. DO NOT EDIT. //go:generate wire //+build !wireinject package main // Injectors from wire.go: func InitMission(name string) Mission { player := NewPlayer(name) monster := NewMonster() mission := NewMission(player, monster) return mission }
You can see that wire automatically generates the InitMission method for us. In this method, player, monster and mission are initialized in sequence. Then we only need to call this InitMission in our main function.
func main() { mission := InitMission("dj") mission.Start() }
Before dependency injection was used, our code looked like this:
func main() { monster := NewMonster() player := NewPlayer("dj") mission := NewMission(player, monster) mission.Start() }
Isn’t it much simpler? There are only three object initializations here. If there were more, you might not realize the benefits of dependency injection.
For example:
wire.go文件: // +build wireinject // The build tag makes sure the stub is not built in the final build. package di import ( "github.com/google/wire" ) //go:generate kratos t wire func InitApp() (*App, func(), error) { panic(wire.Build(dao.Provider, service.Provider, http.New, grpc.New, NewApp)) } 实现文件: //dao var Provider = wire.NewSet(New, NewDB, NewRedis) //service var Provider = wire.NewSet(New, wire.Bind(new(pb.Server), new(*Service))) 生成的wire_gen.go 文件: func InitApp() (*App, func(), error) { redis, cleanup, err := dao.NewRedis() if err != nil { return nil, nil, err } db, cleanup2, err := dao.NewDB() if err != nil { cleanup() return nil, nil, err } daoDao, cleanup3, err := dao.New(redis, db) if err != nil { cleanup2() cleanup() return nil, nil, err } serviceService, cleanup4, err := service.New(daoDao) if err != nil { cleanup3() cleanup2() cleanup() return nil, nil, err } engine, err := http.New(serviceService) if err != nil { cleanup4() cleanup3() cleanup2() cleanup() return nil, nil, err } server, err := grpc.New(serviceService) if err != nil { cleanup4() cleanup3() cleanup2() cleanup() return nil, nil, err } app, cleanup5, err := NewApp(serviceService, engine, server) if err != nil { cleanup4() cleanup3() cleanup2() cleanup() return nil, nil, err } return app, func() { cleanup5() cleanup4() cleanup3() cleanup2() cleanup() }, nil }
So, what exactly is dependency injection?
It’s just encapsulation and decoupling.
【Related recommendations: Go video tutorial, Programming teaching】
The above is the detailed content of What is go language dependency injection?. For more information, please follow other related articles on the PHP Chinese website!