Skip to content

Commit

Permalink
refactor: remove DIContainer abstraction (#196)
Browse files Browse the repository at this point in the history
* fix: Optimized debug message

* refactor: remove di abstraction

* test: fix failed tests

* fix: comment

Co-authored-by: Trock <g_trock@163.com>
  • Loading branch information
Reasno and GGXXLL authored Sep 22, 2021
1 parent 30380dd commit ca53a9b
Show file tree
Hide file tree
Showing 13 changed files with 274 additions and 198 deletions.
29 changes: 17 additions & 12 deletions c.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ package core

import (
"context"
"errors"
"fmt"
"reflect"
"regexp"

"github.com/DoNewsCode/core/codec/yaml"
"github.com/DoNewsCode/core/config"
Expand All @@ -23,10 +21,11 @@ import (
"github.com/go-kit/kit/log"
"github.com/knadh/koanf/providers/confmap"
"github.com/knadh/koanf/providers/file"
"go.uber.org/dig"
)

// C stands for the core of the application. It contains service definitions and
// dependencies. C is mean to be used in the boostrap phase of the application.
// dependencies. C means to be used in the boostrap phase of the application.
// Do not pass C into services and use it as a service locator.
type C struct {
AppName contract.AppName
Expand All @@ -35,7 +34,7 @@ type C struct {
logging.LevelLogger
contract.Container
contract.Dispatcher
di contract.DIContainer
di *dig.Container
}

// ConfParser models a parser for configuration. For example, yaml.Parser.
Expand All @@ -56,8 +55,8 @@ type ConfigProvider func(configStack []config.ProviderSet, configWatcher contrac
// EventDispatcherProvider provides contract.Dispatcher to the core.
type EventDispatcherProvider func(conf contract.ConfigUnmarshaler) contract.Dispatcher

// DiProvider provides the DiContainer to the core.
type DiProvider func(conf contract.ConfigUnmarshaler) contract.DIContainer
// DiProvider provides the *dig.Container to the core.
type DiProvider func(conf contract.ConfigUnmarshaler) *dig.Container

// AppNameProvider provides the contract.AppName to the core.
type AppNameProvider func(conf contract.ConfigUnmarshaler) contract.AppName
Expand Down Expand Up @@ -249,8 +248,15 @@ func (c *C) Provide(deps di.Deps) {
}

func (c *C) provide(constructor interface{}) {

var shouldMakeFunc bool
var (
options []dig.ProvideOption
shouldMakeFunc bool
)

if op, ok := constructor.(di.OptionalProvider); ok {
constructor = op.Constructor
options = op.Options
}

ftype := reflect.TypeOf(constructor)
if ftype == nil {
Expand Down Expand Up @@ -284,7 +290,7 @@ func (c *C) provide(constructor interface{}) {

// no cleanup or module, we can use normal dig.
if !shouldMakeFunc {
err := c.di.Provide(constructor)
err := c.di.Provide(constructor, options...)
if err != nil {
panic(err)
}
Expand All @@ -309,7 +315,8 @@ func (c *C) provide(constructor interface{}) {
}
return filteredOuts
})
err := c.di.Provide(fn.Interface())
options = append(options, dig.LocationForPC(reflect.ValueOf(constructor).Pointer()))
err := c.di.Provide(fn.Interface(), options...)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -408,8 +415,6 @@ func (c *C) AddModuleFunc(constructor interface{}) {
func (c *C) Invoke(function interface{}) {
err := c.di.Invoke(function)
if err != nil {
re := regexp.MustCompile(` missing dependencies for function "reflect"\.makeFuncStub \(.+?\):`)
err = errors.New(re.ReplaceAllString(err.Error(), ""))
panic(err)
}
}
Expand Down
20 changes: 1 addition & 19 deletions contract/di.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,10 @@
package contract

// DIProvider is an interface that models a container to which users can add
// dependencies. See di.Graph for the implementation requirement.
type DIProvider interface {
Provide(constructor interface{}) error
}

// DIInvoker is an interface that models a container to which users can fetch
// dependencies. See di.Graph for the implementation requirement.
type DIInvoker interface {
Invoke(function interface{}) error
}

// DIPopulator is an interface that models a container to which users can fetch
// dependencies. It is an syntax sugar to DIInvoker. See di.Graph for the
// dependencies. It is a syntax sugar to dig.Container. See dig.Container for the
// implementation requirement.
type DIPopulator interface {
// Populate is just another way of fetching dependencies from container. It
// accepts a ptr to target, and populates the target from the container.
Populate(target interface{}) error
}

// DIContainer is a container roughly modeled after dig.Container.
type DIContainer interface {
DIProvider
DIInvoker
}
6 changes: 3 additions & 3 deletions default_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import (

"github.com/DoNewsCode/core/config"
"github.com/DoNewsCode/core/contract"
"github.com/DoNewsCode/core/di"
"github.com/DoNewsCode/core/events"
"github.com/DoNewsCode/core/logging"
"github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"
"github.com/knadh/koanf/parsers/yaml"
"github.com/knadh/koanf/providers/rawbytes"
"go.uber.org/dig"
)

const defaultConfig = `
Expand Down Expand Up @@ -100,8 +100,8 @@ func ProvideLogger(conf contract.ConfigUnmarshaler, appName contract.AppName, en
}

// ProvideDi is the default DiProvider for package Core.
func ProvideDi(conf contract.ConfigUnmarshaler) contract.DIContainer {
return di.NewGraph()
func ProvideDi(conf contract.ConfigUnmarshaler) *dig.Container {
return dig.New()
}

// ProvideEventDispatcher is the default EventDispatcherProvider for package Core.
Expand Down
133 changes: 0 additions & 133 deletions di/graph.go

This file was deleted.

72 changes: 72 additions & 0 deletions di/optional_provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package di

import (
"reflect"

"go.uber.org/dig"
)

// OptionalProvider is a struct with constructor and dig options. When
// OptionalProvider is used as the element in di.Deps, the options are applied to
// the inner dig.Container automatically.
type OptionalProvider struct {
Constructor interface{}
Options []dig.ProvideOption
}

// LocationForPC sets the constructor pointer to a specified location. Use this
// Options to reduce vague debug message when constructor are made by
// reflect.makeFunc. For example:
// LocationForPC(reflect.makeFunc(...), reflect.ValueOf(realConstructor).Pointer())
func LocationForPC(constructor interface{}, pc uintptr) interface{} {
if op, ok := constructor.(OptionalProvider); ok {
op.Options = append(op.Options, dig.LocationForPC(pc))
return op
}
return OptionalProvider{
Constructor: constructor,
Options: []dig.ProvideOption{dig.LocationForPC(pc)},
}
}

// As constructs the instance and bind it to another interface. As means to be used as an argument to graph.Provide.
// For example:
// As(MyConstructor, new(MyAbstractInterface))
func As(constructor interface{}, as interface{}) interface{} {
if op, ok := constructor.(OptionalProvider); ok {
op.Options = append(op.Options, dig.As(as))
return op
}
return OptionalProvider{
Constructor: constructor,
Options: []dig.ProvideOption{dig.As(as)},
}
}

// Name constructs a named instance. Name means to be used as an argument to graph.Provide.
// For example:
// Name(MyConstructor, "foo")
func Name(constructor interface{}, name string) interface{} {
if op, ok := constructor.(OptionalProvider); ok {
op.Options = append(op.Options, dig.Name(name))
return op
}
return OptionalProvider{
Constructor: constructor,
Options: []dig.ProvideOption{dig.Name(name)},
}
}

// Bind binds a type to another. Useful when binding implementation to
// interfaces. The arguments should be a ptr to the binding types, rather than
// the types themselves. For example:
// Bind(new(MyConcreteStruct), new(MyAbstractInterface))
func Bind(from interface{}, to interface{}) interface{} {
fromTypes := []reflect.Type{reflect.TypeOf(from).Elem()}
toTypes := []reflect.Type{reflect.TypeOf(to).Elem()}
fnType := reflect.FuncOf(fromTypes, toTypes, false /* variadic */)
fn := reflect.MakeFunc(fnType, func(args []reflect.Value) []reflect.Value {
return args
})
return fn.Interface()
}
Loading

0 comments on commit ca53a9b

Please sign in to comment.