Go 开源库运行时依赖注入框架 Dependency injection

这篇具有很好参考价值的文章主要介绍了Go 开源库运行时依赖注入框架 Dependency injection。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Dependency injection

一个Go编程语言的运行依赖注入库。依赖注入是更广泛的控制反转技术的一种形式。它用于增加程序的模块化并使其具有可扩展性。

实例展示(High API):

type A struct {
	Name string
}

func NewA() *A {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	name := "A-" + strconv.Itoa(r.Int())
	return &A{Name: ls}
}

services := NewServiceCollection()
services.AddSingleton(NewA)
//serviceCollection.AddSingletonByImplementsAndName("redis-master", NewRedis, new(abstractions.IDataSource))
//serviceCollection.AddTransientByImplements(NewRedisClient, new(redis.IClient))
//serviceCollection.AddTransientByImplements(NewRedisHealthIndicator, new(health.Indicator))
serviceProvider := services.Build()

var env *A
_ = serviceProvider.GetService(&env) // used

依赖注入将如何帮助我们的?

依赖注入是更广泛的控制反转技术的一种形式。它用于增加程序的模块化并使其具有可扩展性。

安装

go get -u github.com/yoyofxteam/dependencyinjection@v1.0.1

组件特性

  • Providing
  • Extraction
  • Invocation
  • Lazy-loading
  • Interfaces
  • Groups
  • Named definitions
  • Optional parameters
  • Parameter Bag
  • Prototypes
  • Cleanup

Providing

首先,我们需要创建两个基本类型:http。服务器和http.ServeMux。让我们创建一个简单的构造函数来初始化它:

// NewServer creates a http server with provided mux as handler.
func NewServer(mux *http.ServeMux) *http.Server {
	return &http.Server{
		Handler: mux,
	}
}

// NewServeMux creates a new http serve mux.
func NewServeMux() *http.ServeMux {
	return &http.ServeMux{}
}

支持的构造器签名形式如下:

func([dep1, dep2, depN]) (result, [cleanup, error])

现在让我们来容器构建这些类型。

下面展示是Low API, 也可以用High API来构建:

import (
  di "github.com/yoyofxteam/dependencyinjection"
)

container := di.New(
	// provide http server
    di.Provide(NewServer),
    // provide http serve mux
    di.Provide(NewServeMux)
)

函数di. new()解析构造函数,编译依赖关系图并返回*di。用于交互的容器类型。如果无法编译,容器会出现恐慌。

我认为在应用程序初始化时而不是在运行时出现恐慌是很常见的。

Extraction

我们可以从容器中提取构建的服务器。为此,定义提取类型的变量,并将变量指针传递给Extract函数。

如果未找到提取的类型或构建实例的过程导致错误,则提取返回错误。
如果没有错误发生,我们就可以使用这个变量,就像我们自己构建它一样。

// declare type variable
var server *http.Server
// extracting
err := container.Extract(&server)
if err != nil {
	// check extraction error
}

server.ListenAndServe()

请注意,默认情况下,容器作为单例创建实例 , 但也可使用Provide做行为上的改变。


## Invocation
作为提取的替代方法,我们可以使用Invoke()函数。它解析函数依赖并调用函数。调用函数可能返回可选错误。
```golang
// NewServer creates a http server with provided mux as handler.
func NewServer(handler http.Handler) *http.Server {
	return &http.Server{
		Handler: handler,
	}
}

对于一个容器来说,要知道作为http的实现。处理程序是必须使用的,我们使用选项di.As()。这个选项的参数必须是一个指向接口的指针,比如new(Endpoint)。

这种语法可能看起来很奇怪,但我还没有找到更好的方式来指定接口。

修改依赖注入容器初始化代码:

container := inject.New(
	// provide http server
	inject.Provide(NewServer),
	// provide http serve mux as http.Handler interface
	inject.Provide(NewServeMux, inject.As(new(http.Handler)))
)

现在容器使用提供*http。ServeMux作为http。服务器构造函数中的处理程序。使用接口有助于编写更多可测试的代码。

Groups

容器自动将接口的所有实现分组到[]组。例如,提供with inject.As(new(http.Handler))自动创建一个组[]http.Handler。

让我们使用这个特性添加一些http控制器。控制器有典型的行为。它正在注册路由。首先,将为它创建一个接口。

// Controller is an interface that can register its routes.
type Controller interface {
	RegisterRoutes(mux *http.ServeMux)
}

现在我们将编写控制器并实现控制器接口。

// OrderController is a http controller for orders.
type OrderController struct {}

// NewOrderController creates a auth http controller.
func NewOrderController() *OrderController {
	return &OrderController{}
}

// RegisterRoutes is a Controller interface implementation.
func (a *OrderController) RegisterRoutes(mux *http.ServeMux) {
	mux.HandleFunc("/orders", a.RetrieveOrders)
}

// Retrieve loads orders and writes it to the writer.
func (a *OrderController) RetrieveOrders(writer http.ResponseWriter, request *http.Request) {
	// implementation
}

UserController

// UserController is a http endpoint for a user.
type UserController struct {}

// NewUserController creates a user http endpoint.
func NewUserController() *UserController {
	return &UserController{}
}

// RegisterRoutes is a Controller interface implementation.
func (e *UserController) RegisterRoutes(mux *http.ServeMux) {
	mux.HandleFunc("/users", e.RetrieveUsers)
}

// Retrieve loads users and writes it using the writer.
func (e *UserController) RetrieveUsers(writer http.ResponseWriter, request *http.Request) {
    // implementation
}

就像在这个接口的例子中,我们将使用inject.As()提供provide选项。

container := inject.New(
	di.Provide(NewServer),        // provide http server
	di.Provide(NewServeMux),       // provide http serve mux
	// endpoints
	di.Provide(NewOrderController, di.As(new(Controller))),  // provide order controller
	di.Provide(NewUserController, di.As(new(Controller))),  // provide user controller
)

现在,我们可以在mux中使用控制器数组。参见更新后的代码:

// NewServeMux creates a new http serve mux.
func NewServeMux(controllers []Controller) *http.ServeMux {
	mux := &http.ServeMux{}

	for _, controller := range controllers {
		controller.RegisterRoutes(mux)
	}

	return mux
}

高级功能

Named definitions

在某些情况下,一种类型有多个实例。例如两个数据库实例:master -用于写,slave -用于读。

// MasterDatabase provide write database access.
type MasterDatabase struct {
	*Database
}

// SlaveDatabase provide read database access.
type SlaveDatabase struct {
	*Database
}

第二种方法是使用带有di.WithName()提供选项的命名定义

// provide master database
di.Provide(NewMasterDatabase, di.WithName("master"))
// provide slave database
di.Provide(NewSlaveDatabase, di.WithName("slave"))

如果需要从容器中提取,请使用di.Name()提取选项。

var db *Database
container.Extract(&db, di.Name("master"))

如果需要在其他构造函数中提供命名定义,请使用di。参数嵌入。

// ServiceParameters
type ServiceParameters struct {
	di.Parameter
	
	// use `di` tag for the container to know that field need to be injected.
	MasterDatabase *Database `di:"master"`
	SlaveDatabase *Database  `di:"slave"`
}

// NewService creates new service with provided parameters.
func NewService(parameters ServiceParameters) *Service {
	return &Service{
		MasterDatabase:  parameters.MasterDatabase,
		SlaveDatabase: parameters.SlaveDatabase,
	}
}

Optional parameters

// ServiceParameter
type ServiceParameter struct {
	di.Parameter
	
	StdOutLogger *Logger `di:"stdout"`
	FileLogger   *Logger `di:"file,optional"`
}

将依赖声明为可选的构造函数必须处理这些依赖不存在的情况。

Parameter Bag

如果需要在定义级别上指定一些参数,则可以使用 inject.ParameterBag provide option. 这是一个map[string]interface{},可以转换为di.ParameterBag类型。

// Provide server with parameter bag
di.Provide(NewServer, di.ParameterBag{
	"addr": ":8080",
})

// NewServer create a server with provided parameter bag. Note: use di.ParameterBag type.
// Not inject.ParameterBag.
func NewServer(pb di.ParameterBag) *http.Server {
	return &http.Server{
		Addr: pb.RequireString("addr"),
	}
}

Prototypes

如果您想在每次提取上创建一个新实例,请使用di.Prototype()提供选项。

di.Provide(NewRequestContext, di.Prototype())

Cleanup

如果提供程序创建了一个需要清理的值,那么它可以返回一个闭包来清理资源。

func NewFile(log Logger, path Path) (*os.File, func(), error) {
    f, err := os.Open(string(path))
    if err != nil {
        return nil, nil, err
    }
    cleanup := func() {
        if err := f.Close(); err != nil {
            log.Log(err)
        }
    }
    return f, cleanup, nil
}

在调用container.Cleanup()之后,它遍历实例,如果存在则调用cleanup函数。

container := di.New(
	// ...
    di.Provide(NewFile),
)

// do something
container.Cleanup() // file was closed

总结

Dependency injection 是一个运行时的依赖注入框架, 它也会集成到了微服务框架 yoyogo 中. 🦄🌈 YoyoGo (Go语言框架)一个简单、轻量、快速、基于依赖注入的微服务框架( web 、grpc ),支持Nacos/Consoul/Etcd/Eureka/k8s /Apollo等 .

参考:

yoyogo: https://github.com/yoyofx/yoyogo

dependencyinjection: https://github.com/yoyofxteam/dependencyinjection文章来源地址https://www.toymoban.com/news/detail-468265.html

到了这里,关于Go 开源库运行时依赖注入框架 Dependency injection的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Vue 中的依赖注入,特别是 Provide 和 Inject,它们的原理、用法和示例

    Vue.js 作为一款现代的前端 JavaScript 框架,提供了诸多方便开发的特性。其中依赖注入是一个非常有用的功能,可以在组件树中传递数据和方法,并使得组件之间的耦合度更低。本文将介绍 Vue 中的依赖注入,特别是 Provide 和 Inject,它们的原理、用法和示例。 在软件开发中,

    2024年02月06日
    浏览(36)
  • Langchain框架 prompt injection注入

    Prompt Injection 是一种攻击技术,黑客或恶意攻击者操纵 AI 模型的输入值,以诱导模型返回非预期的结果 LangChain 是一个基于大语言模型进行应用开发的框架。 所谓大语言模型(Large Language Models, LLMs),是指基于海量语料训练、参数动辄数十亿上百亿的语言模型。除了大家熟知

    2024年02月01日
    浏览(34)
  • 测试框架pytest教程(2)-用例依赖库-pytest-dependency

    对于 pytest 的用例依赖管理,可以使用  pytest-dependency  插件。该插件提供了更多的依赖管理功能,使你能够更灵活地定义和控制测试用例之间的依赖关系。 Using pytest-dependency — pytest-dependency 0.5.1 documentation 安装 pytest-dependency 插件: 依赖方法和被依赖方法都需要使用装饰器

    2024年02月11日
    浏览(25)
  • go 语言实现依赖注入

    依赖注入和控制反转恰恰相反,它是一种具体的编码技巧。我们不通过 new 的方式在类内部创建依赖类的对象,而是将依赖的类对象在外部创建好之后,通过构造函数、函数参数等方式传递(或注入)给类来使用。 DI(依赖性注入)是一种技术,当你的模块间接地接受依赖性

    2024年01月17日
    浏览(46)
  • 快速学Go依赖注入工具wire

    Go相对java和C++是较新的语言,但也有诸多优秀特性及生态库。本文介绍大多数软件工程中常用的功能:依赖注入。首先介绍什么是依赖注入,go实现库wire与其他语言的差异。然后通过简单示例实现依赖注入,简化代码、提升可读性。 依赖注入是一种对象接收它所依赖的其他对

    2024年02月05日
    浏览(37)
  • go依赖注入库samber/do使用

    英语版本 以简单和高效而闻名的Go语言在其1.18版本中引入了泛型,这可以显着减少大量代码生成的需要,使该语言更加强大和灵活。如果您有兴趣, Go 泛型教程 是很好的学习资源。 通过使用 Go 的泛型,samber/do库为依赖注入 (DI) 提供了一个很好的解决方案。依赖注入是一种

    2024年02月19日
    浏览(28)
  • Go 项目依赖注入wire工具最佳实践介绍与使用

    目录 一、引入 二、控制反转与依赖注入 三、为什么需要依赖注入工具 3.1 示例 3.2 依赖注入写法与非依赖注入写法 四、wire 工具介绍与安装 4.1 wire 基本介绍 4.2 安装 五、Wire 的基本使用 5.1 前置代码准备 5.2 使用 Wire 工具生成代码 六、Wire 核心技术 5.1 抽象语法树分析 5.2 模板

    2024年04月08日
    浏览(30)
  • Understanding Dependency Injection for angular

    Angular https://angular.io/guide/dependency-injection Denpendency Injection,  or DI, is one of fundamental concepts for angular, DI is writed by angular framework and allows classes with  Angular decorators,  such as Components, directives, Piples and Injectables , to configure dependencies that they need.  Two main roles exists in DI system: dependency

    2024年02月10日
    浏览(25)
  • Android Hilt依赖注入框架

    Hilt 是一个基于 Dagger2 的依赖注入框架,它提供了一些简便的注入方式来简化开发者在 Android 应用中使用 Dagger2 的复杂性。Hilt 旨在简化 Android 应用程序中的依赖注入实现,使开发人员能够更轻松地管理依赖项和应用程序的组件。 Hilt 的主要目标是提供一种简单的方式来管理应

    2023年04月22日
    浏览(30)
  • ASP.NET Core 中的 Dependency injection

    依赖注入 (Dependency Injection,简称DI)是为了实现 各个类之间的依赖 的 控制反转 (Inversion of Control,简称IoC )。 ASP.NET Core 中的Controller 和 Service 或者其他类都支持依赖注入。 依赖注入术语中, Service 是一个为其他对象提供服务的类 **。 Service 不是一个Web Service,与Web Serv

    2024年02月11日
    浏览(25)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包