Skip to content

Commit

Permalink
change project name to go-ioc
Browse files Browse the repository at this point in the history
  • Loading branch information
mylxsw committed Nov 28, 2022
1 parent 8c02694 commit d2e41b5
Show file tree
Hide file tree
Showing 14 changed files with 456 additions and 400 deletions.
24 changes: 10 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Container
# Go-IOC

[![Build Status](https://www.travis-ci.org/mylxsw/container.svg?branch=master)](https://www.travis-ci.org/mylxsw/container)
[![Coverage Status](https://coveralls.io/repos/github/mylxsw/container/badge.svg?branch=master)](https://coveralls.io/github/mylxsw/container?branch=master)
Expand All @@ -8,21 +8,21 @@
[![GitHub](https://img.shields.io/github/license/mylxsw/container.svg)](https://github.com/mylxsw/container)


**Container** 是一款为 Go 语言开发的运行时依赖注入库。Go 语言的语言特性决定了实现一款类型安全的依赖注入容器并不太容易,因此 **Container** 大量使用了 Go 的反射机制。如果你的使用场景对性能要求并不是那个苛刻,那 **Container** 非常适合你。
**Go-IOC** 是一款为 Go 语言开发的运行时依赖注入库。Go 语言的语言特性决定了实现一款类型安全的依赖注入容器并不太容易,因此 **Go-IOC** 大量使用了 Go 的反射机制。如果你的使用场景对性能要求并不是那个苛刻,那 **Go-IOC** 非常适合你。

> 并不是说对性能要求苛刻的环境中就不能使用了,你可以把 **Container** 作为一个对象依赖管理工具,在你的业务初始化时获取依赖的对象。
> 并不是说对性能要求苛刻的环境中就不能使用了,你可以把 **Go-IOC** 作为一个对象依赖管理工具,在你的业务初始化时获取依赖的对象。
使用方式

go get github.com/mylxsw/container
go get github.com/mylxsw/go-ioc

要创建一个 **Container** 实例,使用 `containier.New` 方法
要创建一个 **Container** 实例,使用 `ioc.New` 方法

cc := container.New()
cc := ioc.New()

此时就创建了一个空的容器。

> 你也可以使用 `container.NewWithContext(ctx)` 来创建容器,创建之后,可以自动的把已经存在的 `context.Context` 对象添加到容器中,由容器托管。
> 你也可以使用 `ioc.NewWithContext(ctx)` 来创建容器,创建之后,可以自动的把已经存在的 `context.Context` 对象添加到容器中,由容器托管。
## 对象绑定

Expand Down Expand Up @@ -120,7 +120,7 @@

### Resolve

`Resolve(callback interface{}) error` 方法执行体 callback 内部只能进行依赖注入,不接收注入函数的返回值,虽然有一个 `error` 返回值,但是该值只表明是否在注入对象时产生错误
`Resolve(callback interface{}) error` 方法执行体 callback 内部能够进行依赖注入,`error` 返回值,表明在注入对象时产生错误或者 callback 返回了 error

比如,我们需要获取某个用户的信息和其角色信息,使用 Resolve 方法

Expand All @@ -136,11 +136,7 @@
// do something you want with user/role
})

直接使用 `Resolve` 方法可能并不太满足我们的日常业务需求,因为在执行查询的时候,总是会遇到各种 `error`,直接丢弃会产生很多隐藏的 Bug,但是我们也不倾向于使用 `Panic` 这种暴力的方式来解决。

**Container** 提供了 `ResolveWithError(callback interface{}) error` 方法,使用该方法时,我们的 callback 可以接受一个 `error` 返回值,来告诉调用者这里出现问题了。

err := cc.ResolveWithError(func(userRepo repo.UserRepo, roleRepo repo.RoleRepoo) error {
err := cc.Resolve(func(userRepo repo.UserRepo, roleRepo repo.RoleRepoo) error {
user, err := userRepo.GetUser(123)
if err != nil {
return err
Expand Down Expand Up @@ -271,7 +267,7 @@ WithCondition(init interface{}, onCondition interface{}) Conditional
## 示例项目

简单的示例可以参考项目的 [example](https://github.com/mylxsw/container/tree/master/example) 目录。
简单的示例可以参考项目的 [example](https://github.com/mylxsw/go-ioc/tree/master/example) 目录。

以下项目中使用了 `Container` 作为依赖注入管理库,感兴趣的可以参考一下。

Expand Down
63 changes: 26 additions & 37 deletions bind.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
package container
package ioc

import "reflect"

// BindValue bind a value to container
func (impl *containerImpl) BindValue(key string, value interface{}) error {
func (impl *container) BindValue(key string, value interface{}) error {
return impl.bindValueOverride(key, value, false)
}

// HasBoundValue return whether the kay has bound to a value
func (impl *containerImpl) HasBoundValue(key string) bool {
func (impl *container) HasBoundValue(key string) bool {
impl.lock.RLock()
defer impl.lock.RUnlock()

_, ok := impl.objects[key]
_, ok := impl.entities[key]
return ok
}

func (impl *containerImpl) bindValueOverride(key string, value interface{}, override bool) error {
func (impl *container) bindValueOverride(key string, value interface{}, override bool) error {
if value == nil {
return buildInvalidArgsError("value is nil")
}
Expand All @@ -33,59 +33,54 @@ func (impl *containerImpl) bindValueOverride(key string, value interface{}, over
key: key,
typ: reflect.TypeOf(value),
value: value,
override: override,
index: len(impl.objectSlices),
overridable: override,
c: impl,
prototype: false,
}

if original, ok := impl.objects[key]; ok {
if !original.override {
return buildRepeatedBindError("key repeated, override is not allowed for this key")
if v, ok := impl.entities[key]; ok {
if !v.overridable {
return buildRepeatedBindError("key repeated, overridable is not allowed for this key")
}

entity.index = original.index
impl.objects[key] = &entity
impl.objectSlices[original.index] = &entity

impl.entities[key] = &entity
return nil
}

impl.objects[key] = &entity
impl.objectSlices = append(impl.objectSlices, &entity)
impl.entities[key] = &entity

return nil
}

// BindValueOverride bind a value to container, if key already exist, then replace it
func (impl *containerImpl) BindValueOverride(key string, value interface{}) error {
func (impl *container) BindValueOverride(key string, value interface{}) error {
return impl.bindValueOverride(key, value, true)
}

// MustBindValueOverride bind a value to container, if key already exist, then replace it, if failed, panic it
func (impl *containerImpl) MustBindValueOverride(key string, value interface{}) {
func (impl *container) MustBindValueOverride(key string, value interface{}) {
impl.Must(impl.BindValueOverride(key, value))
}

// MustBindValue bind a value to container, if failed, panic it
func (impl *containerImpl) MustBindValue(key string, value interface{}) {
func (impl *container) MustBindValue(key string, value interface{}) {
impl.Must(impl.BindValue(key, value))
}

// HasBound return whether a key's type has bound to an object
func (impl *containerImpl) HasBound(key interface{}) bool {
func (impl *container) HasBound(key interface{}) bool {
keyTyp := reflect.ValueOf(key).Type()

impl.lock.RLock()
defer impl.lock.RUnlock()

_, ok := impl.objects[keyTyp]
_, ok := impl.entities[keyTyp]
return ok
}

// BindWithKey bind a initialize for object with a key
// initialize func(...) (value, error)
func (impl *containerImpl) BindWithKey(key interface{}, initialize interface{}, prototype bool, override bool) error {
func (impl *container) BindWithKey(key interface{}, initialize interface{}, prototype bool, override bool) error {
if _, ok := initialize.(Conditional); !ok {
initialize = WithCondition(initialize, func() bool { return true })
}
Expand Down Expand Up @@ -114,13 +109,13 @@ func (impl *containerImpl) BindWithKey(key interface{}, initialize interface{},
}

// MustBindWithKey bind a initialize for object with a key, if failed then panic
func (impl *containerImpl) MustBindWithKey(key interface{}, initialize interface{}, prototype bool, override bool) {
func (impl *container) MustBindWithKey(key interface{}, initialize interface{}, prototype bool, override bool) {
impl.Must(impl.BindWithKey(key, initialize, prototype, override))
}

// Bind bind a initialize for object
// initialize func(...) (value, error)
func (impl *containerImpl) Bind(initialize interface{}, prototype bool, override bool) error {
func (impl *container) Bind(initialize interface{}, prototype bool, override bool) error {
if _, ok := initialize.(Conditional); !ok {
initialize = conditional{init: initialize, on: func() bool { return true }}
}
Expand Down Expand Up @@ -155,11 +150,11 @@ func (impl *containerImpl) Bind(initialize interface{}, prototype bool, override
}

// MustBind bind a initialize, if failed then panic
func (impl *containerImpl) MustBind(initialize interface{}, prototype bool, override bool) {
func (impl *container) MustBind(initialize interface{}, prototype bool, override bool) {
impl.Must(impl.Bind(initialize, prototype, override))
}

func (impl *containerImpl) bindWithOverride(key interface{}, typ reflect.Type, initialize interface{}, prototype bool, override bool) error {
func (impl *container) bindWithOverride(key interface{}, typ reflect.Type, initialize interface{}, prototype bool, override bool) error {
var entity *Entity
if cond, ok := initialize.(Conditional); ok {
matched, err := cond.matched(impl)
Expand All @@ -179,22 +174,16 @@ func (impl *containerImpl) bindWithOverride(key interface{}, typ reflect.Type, i
impl.lock.Lock()
defer impl.lock.Unlock()

if original, ok := impl.objects[key]; ok {
if !original.override {
return buildRepeatedBindError("key repeated, override is not allowed for this key")
if v, ok := impl.entities[entity.key]; ok {
if !v.overridable {
return buildRepeatedBindError("key repeated, overridable is not allowed for this key")
}

entity.index = original.index
impl.objects[key] = entity
impl.objectSlices[original.index] = entity

impl.entities[key] = entity
return nil
}

entity.index = len(impl.objectSlices)

impl.objects[key] = entity
impl.objectSlices = append(impl.objectSlices, entity)
impl.entities[key] = entity

return nil
}
6 changes: 3 additions & 3 deletions condition.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package container
package ioc

import (
"errors"
Expand All @@ -19,8 +19,8 @@ type conditional struct {
// WithCondition 创建 Conditional 接口实例
// init 参数为传递个 Singleton/Prototype 方法的实例创建方法
// onCondition 参数支持两种形式
// - `onCondition(依赖注入参数列表...) bool`
// - `onCondition(依赖注入参数列表...) (bool, error)`
// - `onCondition(依赖注入参数列表...) bool`
// - `onCondition(依赖注入参数列表...) (bool, error)`
func WithCondition(init interface{}, onCondition interface{}) Conditional {
if onCondition == nil {
panic("invalid argument onCondition: can not be nil [onCondition() bool or onCondition() (bool, error)]")
Expand Down
Loading

0 comments on commit d2e41b5

Please sign in to comment.