Coder Social home page Coder Social logo

alibaba / ioc-golang Goto Github PK

View Code? Open in Web Editor NEW
1.2K 22.0 119.0 1.25 MB

一款服务于 Go 开发者的依赖注入框架,方便搭建任何 Go 应用。 A Golang depenedency injection framework, helps developers to build any go application.

Home Page: https://ioc-golang.github.io

License: Apache License 2.0

Makefile 0.44% Go 99.56%
annotation aop debug dependency-injection golang middleware monkey sdk tag

ioc-golang's Introduction

IOC-golang: A golang dependency injection framework

  ___    ___     ____                           _                         
 |_ _|  / _ \   / ___|           __ _    ___   | |   __ _   _ __     __ _ 
  | |  | | | | | |      _____   / _` |  / _ \  | |  / _` | | '_ \   / _` |
  | |  | |_| | | |___  |_____| | (_| | | (_) | | | | (_| | | | | | | (_| |
 |___|  \___/   \____|          \__, |  \___/  |_|  \__,_| |_| |_|  \__, |
                                |___/                               |___/ 

IOC-golang CI License

English | 中文

demo gif

IOC-golang is a powerful golang dependency injection framework that provides a complete implementation of IoC containers. Its capabilities are as follows:

Dependency Injection

  • Supports dependency injection of any structure and interface, we also support object life cycle management mechanism

  • Can take over object creation, parameter injection, factory methods. Customizable object parameter source

Struct Proxy

  • Based on the idea of AOP, we provide struct proxy layer for all struct registered to ioc-golang. In the scene of interface oriented development, we can use many devlops features based on the extenablility of this proxy AOP layer. Such as interface listing, param value watching, method level tracing, performance badpoint analysis, fault injection, method level tracing in distributed system and so on.

Automatic struct descriptor codes generation capability

  • We provide a code generation tool, and developers can annotate the structure through annotations, so as to easily generate structure registration code.

Scalability

  • Support the extension of struct to be injected, the extension of autowire model, and the extension of the debug AOP layer.

Many pre-defined components

  • Provides pre-defined objects and middleware sdk for injection directly.

Project Structure

  • aop: Debug module: Provide debugging API, provide debugging injection layer basic implementation and extendable API.
  • autowire: Provides two basic injection models: singleton model and multi-instance model
  • config: Configuration loading module, responsible for parsing ion-golang's configuration files
  • extension: Component extension directory: Provides preset implementation structures based on various domain. Such as database, cache, pubs.
  • example: example repository
  • iocli: code generation/program debugging tool

Quick start

Install code generation tools

% go install github.com/alibaba/ioc-golang/[email protected]
% iocli
hello

Dependency Injection Tutorial

We will develop a project with the following topology, This tutorial can show:

  1. Registry codes generation
  2. Interface injection
  3. Struct pointer injection
  4. Get object by API
  5. Debug capability, list interface, implementations and methods; watch real-time param and return value.

ioc-golang-quickstart-structure

All the code the user needs to write: main.go

package main

import (
	"fmt"
	"time"

	"github.com/alibaba/ioc-golang"
)

// +ioc:autowire=true
// +ioc:autowire:type=singleton

type App struct {
	// inject main.ServiceImpl1 pointer to Service interface with proxy wrapper
	ServiceImpl1 Service `singleton:"main.ServiceImpl1"`

	// inject main.ServiceImpl2 pointer to Service interface with proxy wrapper
	ServiceImpl2 Service `singleton:"main.ServiceImpl2"`

	// inject ServiceImpl1 pointer to Service1 's own interface with proxy wrapper
	// this interface belongs to ServiceImpl1, there is no need to mark 'main.ServiceImpl1' in tag
	Service1OwnInterface ServiceImpl1IOCInterface `singleton:""`

	// inject ServiceStruct struct pointer
	ServiceStruct *ServiceStruct `singleton:""`
}

func (a *App) Run() {
	for {
		time.Sleep(time.Second * 3)
		fmt.Println(a.ServiceImpl1.GetHelloString("laurence"))
		fmt.Println(a.ServiceImpl2.GetHelloString("laurence"))

		fmt.Println(a.Service1OwnInterface.GetHelloString("laurence"))
		
		fmt.Println(a.ServiceStruct.GetString("laurence"))
	}
}

type Service interface {
	GetHelloString(string) string
}

// +ioc:autowire=true
// +ioc:autowire:type=singleton

type ServiceImpl1 struct {
}

func (s *ServiceImpl1) GetHelloString(name string) string {
	return fmt.Sprintf("This is ServiceImpl1, hello %s", name)
}

// +ioc:autowire=true
// +ioc:autowire:type=singleton

type ServiceImpl2 struct {
}

func (s *ServiceImpl2) GetHelloString(name string) string {
	return fmt.Sprintf("This is ServiceImpl2, hello %s", name)
}

// +ioc:autowire=true
// +ioc:autowire:type=singleton

type ServiceStruct struct {
}

func (s *ServiceStruct) GetString(name string) string {
	return fmt.Sprintf("This is ServiceStruct, hello %s", name)
}

func main() {
	// start to load all structs
	if err := ioc.Load(); err != nil {
		panic(err)
	}

	// Get Struct
	app, err := GetAppSingleton()
	if err != nil {
		panic(err)
	}
	app.Run()
}

The proxy wrapped layer mentioned above, is a proxy layer injected by ioc-golang by default, when developer want to inject an object to interface field, or get with interface by API. Inject to interface is recommended by us. Every object injected with proxy wrapped layer would have devops feature.

After writing, you can exec the following cli command to init go mod and generate codes. (mac may require sudo due to permissions during code generation)

% go mod init ioc-golang-demo
% export GOPROXY="https://goproxy.cn"
% go mod tidy
% go get github.com/alibaba/ioc-golang@master
% sudo iocli gen

It will be generated in the current directory: zz_generated.ioc.go, developers do not need to care about this file, 'GetAppSingleton' method mentioned above is defined in generated code.

//go:build !ignore_autogenerated
// +build !ignore_autogenerated

// Code generated by iocli

package main

import (
        autowire "github.com/alibaba/ioc-golang/autowire"
        normal "github.com/alibaba/ioc-golang/autowire/normal"
        "github.com/alibaba/ioc-golang/autowire/singleton"
        util "github.com/alibaba/ioc-golang/autowire/util"
)

func init() {
        normal.RegisterStructDescriptor(&autowire.StructDescriptor{
                Factory: func() interface{} {
                        return &app_{}
                },
        })
        singleton.RegisterStructDescriptor(&autowire.StructDescriptor{
                Factory: func() interface{} {
                        return &App{}
                },
        })
  ...
func GetServiceStructIOCInterface() (ServiceStructIOCInterface, error) {
        i, err := singleton.GetImplWithProxy(util.GetSDIDByStructPtr(new(ServiceStruct)), nil)
        if err != nil {
                return nil, err
        }
        impl := i.(ServiceStructIOCInterface)
        return impl, nil
}

See the file tree:

% tree
.
├── go.mod
├── go.sum
├── main.go
└── zz_generated.ioc.go

0 directories, 4 files

Execute program

go run .

Console printout:

  ___    ___     ____                           _                         
 |_ _|  / _ \   / ___|           __ _    ___   | |   __ _   _ __     __ _ 
  | |  | | | | | |      _____   / _` |  / _ \  | |  / _` | | '_ \   / _` |
  | |  | |_| | | |___  |_____| | (_| | | (_) | | | | (_| | | | | | | (_| |
 |___|  \___/   \____|          \__, |  \___/  |_|  \__,_| |_| |_|  \__, |
                                |___/                               |___/ 
Welcome to use ioc-golang!
[Boot] Start to load ioc-golang config
[Config] Load default config file from ../conf/ioc_golang.yaml
[Config] Load ioc-golang config file failed. open /Users/laurence/Desktop/workplace/alibaba/conf/ioc_golang.yaml: no such file or directory
 The load procedure is continue
[Boot] Start to load debug
[Debug] Debug port is set to default :1999
[Boot] Start to load autowire
[Autowire Type] Found registered autowire type normal
[Autowire Struct Descriptor] Found type normal registered SD main.serviceStruct_
[Autowire Struct Descriptor] Found type normal registered SD main.app_
[Autowire Struct Descriptor] Found type normal registered SD main.serviceImpl1_
[Autowire Struct Descriptor] Found type normal registered SD main.serviceImpl2_
[Autowire Type] Found registered autowire type singleton
[Autowire Struct Descriptor] Found type singleton registered SD main.App
[Autowire Struct Descriptor] Found type singleton registered SD main.ServiceImpl1
[Autowire Struct Descriptor] Found type singleton registered SD main.ServiceImpl2
[Autowire Struct Descriptor] Found type singleton registered SD main.ServiceStruct
[Debug] Debug server listening at :1999
This is ServiceImpl1, hello laurence
This is ServiceImpl2, hello laurence
This is ServiceImpl1, hello laurence
This is ServiceStruct, hello laurence
...

It shows that the injection is successful and the program runs normally.

Debug the app

Following logs can be found in console output:

[Debug] Debug server listening at :1999

Open a new console, use iocli 's debug feature to list all structs with proxy layer, and their methods. Default port is 1999.

% iocli list
main.ServiceImpl1
[GetHelloString]

main.ServiceImpl2
[GetHelloString]

Watch real-time param and return value. We take main.ServiceImpl 's 'GetHelloString' method as an example. The method would be called twice every 3s :

% iocli watch main.ServiceImpl1 GetHelloString
========== On Call ==========
main.ServiceImpl1.GetHelloString()
Param 1: (string) (len=8) "laurence"

========== On Response ==========
main.ServiceImpl1.GetHelloString()
Response 1: (string) (len=36) "This is ServiceImpl1, hello laurence"

========== On Call ==========
main.ServiceImpl1.GetHelloString()
Param 1: (string) (len=8) "laurence"

========== On Response ==========
main.ServiceImpl1.GetHelloString()
Response 1: (string) (len=36) "This is ServiceImpl1, hello laurence"
...

Annotation Analysis

// +ioc:autowire=true
The code generation tool recognizes objects marked with the +ioc:autowire=true annotation

// +ioc:autowire:type=singleton
The marker autowire model is the singleton

More

Docs

More code generation annotations can be viewed at iocli.

You can go to ioc-golang/example for more examples and advanced usage.

You can go to E-commercial system demo based on ioc-golang to refer to applications system on distributed scene.

License

IOC-golang developed by Alibaba and licensed under the Apache License (Version 2.0). See the NOTICE file for more information.

Connect with us

Welcome to join dingtalk group 44638289 if you are interested with the project.

Star me please ⭐

If you think this project is interesting, or helpful to you, please give a star!

ioc-golang's People

Contributors

alibaba-oss avatar laurencelizhixin avatar nicolerobin avatar photowey avatar tlc-10 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ioc-golang's Issues

[Proposal] Enhance config file load env variables.

IOC-golang 配置文件加载方案

IOC-golang 框架配置文件格式为yaml格式,可以通过API的方式来制定配置加载。在本说明中,将给出配置加载的概念和规则。

1. 参数

SearchPath,[]string类型,表示配置搜索路径,会尝试搜索这些文件夹下的所有文件。

ConfigType,string类型,配置文件格式,目前支持 yaml、yml,默认yml

ConfigName,string类型,需要被加载的配置文件名称。

Profile,[]string 类型,需要被激活的配置文件后缀。如果在 API 中指定激活的 profile 为 “dev", ConfigName 为 "application", 则会从指定文件目录下加载 “application_dev.yaml" ,可同时加载多个profile,框架会对这些配置进行合并。

2. 参数加载方式

配置加载的参数可以通过 API 指定,也可以通过环境变量指定,API方式优先。

2.1 API 方式指定参数

  • config.WithSearchPath("./configs")

    指定需要搜索配置的文件夹路径,可指定多个

  • config.WithConfigType("yaml")

    指定筛选出的配置文件类型,支持 yaml,yml,默认yml

  • config.WithConfigName("app")

    指定需要加载的配置文件名

  • config.WithProfilesActive("dev")

    指定激活的profile,可指定多个

例如:

import(
	"github.com/alibaba/ioc-golang"
	"github.com/alibaba/ioc-golang/config"
)

func main(){
  if err := ioc.Load(
    config.WithSearchPath("./configs"),
    config.WithConfigType("yaml"),
    config.WithConfigName("app"),
    config.WithProfilesActive("dev")); err != nil {
		panic(err)
	}
}

将从./configs/文件夹下加载 app_dev.yaml 文件作为配置,基于这份配置启动框架。

2.2 环境变量指定参数

  • export IOC_GOLANG_CONFIG_SEARCH_PATH="/home/root/app/config"

    指定需要搜索配置的文件夹绝对路径,使用',' 分割,可指定多个。

  • export IOC_GOLANG_CONFIG_TYPE="yaml"

    指定筛选出的配置文件类型,支持 yaml,yml,默认yml

  • export IOC_GOLANG_CONFIG_NAME="app"

    指定需要加载的配置文件名

  • export IOC_GOLANG_CONFIG_ACTIVE_PROFILE="dev"

    指定激活的profile,可指定多个

环境变量指定的内容会被 API 覆盖。

3. 配置文件筛选逻辑示意图

图片

4. 无配置文件启动

配置文件一般存放业务配置数据,框架启动不强依赖配置文件,配置文件加载失败会打印如下日志, 框架继续正常启动。

[Config] Load ioc-golang config file failed. open xxx/xxx/ioc_golang.yaml: no such file or directory
 The load procedure is continue

[Proposal] Transaction support

We should support 'method' level transaction. once error occurs, call previous actions would rollout. In distributed system, all previous methods in the invocation trace should rollout too.

[proposal] Add extendable api for debug interceptor

Now debug api only support pre-set edit and watch interceptor, we should make interceptor extendable and let developers to define their own interceptor, e.g. An interceptor to collect the request timeout of a specific interface, a specific method, specific user.

The interceptor interface would be defined as:

type Interceptor interface {
	Invoke(ctx *common.InterceptorContext, value []reflect.Value) ([]reflect.Value, error) // 
	Name() string // the name of this interceptor, used when logging
}

type PriorityInterceptor interface {
	Interceptor
	Priority() int // all interceptors are sorted by priority
}

The InterceptorContext would be

type InterceptorContext struct {
	context.Context // raw context
	sdid    string // struct description id
	method  string // current invoking method name
	isParam bool // true is param, false is return value.
}

Deverlopers can get current invocation info from InterceptorContext, and also can write metadata into raw context, the raw context would pass through all requests and responses interceptor by priority order.

Deverlopers API

// RegisterInterceptor register interceptor with priority default set to 0
func RegisterInterceptor(inter interceptor.Interceptor) {}

// RegisterPriorityInterceptor register priorityInterceptor 
func RegisterPriorityInterceptor(priorityInterceptor interceptor.PriorityInterceptor) {}

[Proposal] Support mock interface code generation, refer to mockery cli tool.

Golang object mock test can be solved by two ways: mock interface and monkey function. The previous one is more stable. On the scene of ioc-golang, we support struct own interface generation, which means that all structs with managed by ioc can be trated as interface, and have the ability to generate mock stub by mockery cli tool
I think in the near future, we can add mockery mock interface stub generation feature in iocli tools, to help developers to write mock test quickly. The feature is default supported and can be enabled using command line param or annotation like
+ioc:mockery:enable=true

[proposal]: A few suggestions for container design

A few suggestions for design:
1.Register  `Bean` instance uses a unified entry.
2.Get `Bean` instance by a unified entry.

1.#1

// now
// singleton register
func init() {
	singleton.RegisterStructDescriptor(&autowire.StructDescriptor{
	})
}

// prototype register
normal.RegisterStructDescriptor(&autowire.StructDescriptor{
	})
}

Notes: beanfactory is just an alias, it can also be named "ioc" or "beanMap" etc.

// optimization
// singleton register
func init() {
	beanfactory.Register(&autowire.StructDescriptor{
        Scope: "singleton"
	})
}

// prototype register
func init() {
    beanfactory.Register(&autowire.StructDescriptor{
            Scope: "prototype"
        })
    } 
}

2.#2

// now
// appInterface, err := singleton.GetImpl("App-App")


// optimization
// type.1
beanfactory.GetBean("App") // Names like App-App are repeated
beanfactory.GetImpl("App")
// -> App is the struct name


// type.2
beanfactory.GetBean(sdid.APP) 
// -> sdid: a const package generated by cli
// -> APP:struct-name or alias

// type.3
beanfactory.GetBean("Redis-Impl") // SDID: hard-code
beanfactory.GetBean(sdid.RedisImpl)
beanfactory.GetBean(sdid.RedisClient) // Redis-RedisClient


// generated code such as:
// package sdid
//
// const (
//     App string = "App" // App-App
//     RedisImpl string = "Redis-Impl"
//     RedisClient string = "Redis-Impl"
// )


// type.4
// add annotation, such as: component or beanname

// +ioc:autowired=true
// +ioc:autowired:scope=singleton
// +ioc:autowired:component=component-name // +ioc:autowired:beanname=bean-name
type App struct {}

beanfactory.GetBean(${component-name})
beanfactory.GetBean(${bean-name})

[Enhancement] Add comment in zz_generated.ioc.go

At present, the zz_generated.ioc.go file generated by the framework is not readable, so it is necessary to add Chinese and English explanations to the generated code, namely the meaning and purpose of each module. Such as:

// struct descriptor registry, these code contains all life cycle definition of the defined struct.
// 结构描述符定义部分,该部分包含了提供结构的生命周期信息。
func init() {
	normal.RegisterStructDescriptor(&autowire.StructDescriptor{
		Factory: func() interface{} {
			return &app_{}
		},
	})
...

// GetApp is getter function of App struct, it returns App struct pointer
// GetApp 是 App 结构的 get 方法,可以返回 App 结构指针
func GetApp() (*App, error) {
	i, err := singleton.GetImpl(util.GetSDIDByStructPtr(new(App)), nil)
	if err != nil {
		return nil, err
	}
	impl := i.(*App)
	return impl, nil
}

// GetAppIOCInterface is getter function of App owned interface 'AppIOCInterface', the returned interface contains proxy layer.
// GetAppIOCInterface 是 App 结构专属接口的 get 方法,他返回的接口封装了 App 结构的代理层。
func GetAppIOCInterface() (AppIOCInterface, error) {
	i, err := singleton.GetImplWithProxy(util.GetSDIDByStructPtr(new(App)), nil)
	if err != nil {
		return nil, err
	}
	impl := i.(AppIOCInterface)
	return impl, nil
}

问:为什么生成方式选择了采用 wire 类似的编译时生成。而不是 go-spring 类似的运行时注入

https://github.com/go-spring/go-spring

目前看起来当前项目的能力远远不够易用。
比如我们在 Java 里面使用的时候就有一个场景

我们希望把实现统一接口的 bean list 注入进来。
目前看当前接口是完全做不到的。

而且我们可能还需要有一些服务启动和结束的钩子给我们提供出来。目前也是没有看到的

[BUG] can not execute demo code

go.mod

module ioc-golang-demo

go 1.17

require github.com/alibaba/ioc-golang v0.0.0-20220711080411-55cecceea4dc

require (
	github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect
	github.com/alibaba/ioc-golang/extension v0.0.0-20220707071909-d19576eea84e // indirect
	github.com/davecgh/go-spew v1.1.1 // indirect
	github.com/fatih/color v1.13.0 // indirect
	github.com/gin-contrib/sse v0.1.0 // indirect
	github.com/gin-gonic/gin v1.8.1 // indirect
	github.com/glory-go/monkey v1.0.3 // indirect
	github.com/go-playground/locales v0.14.0 // indirect
	github.com/go-playground/universal-translator v0.18.0 // indirect
	github.com/go-playground/validator/v10 v10.11.0 // indirect
	github.com/goccy/go-json v0.9.7 // indirect
	github.com/golang/protobuf v1.5.2 // indirect
	github.com/json-iterator/go v1.1.12 // indirect
	github.com/leodido/go-urn v1.2.1 // indirect
	github.com/mattn/go-colorable v0.1.12 // indirect
	github.com/mattn/go-isatty v0.0.14 // indirect
	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
	github.com/modern-go/reflect2 v1.0.2 // indirect
	github.com/opentracing/opentracing-go v1.2.0 // indirect
	github.com/pelletier/go-toml/v2 v2.0.1 // indirect
	github.com/petermattis/goid v0.0.0-20220526132513-07eaf5d0b9f4 // indirect
	github.com/pkg/errors v0.9.1 // indirect
	github.com/pmezard/go-difflib v1.0.0 // indirect
	github.com/stretchr/objx v0.4.0 // indirect
	github.com/stretchr/testify v1.8.0 // indirect
	github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect
	github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
	github.com/ugorji/go/codec v1.2.7 // indirect
	go.uber.org/atomic v1.9.0 // indirect
	golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
	golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 // indirect
	golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
	golang.org/x/text v0.3.7 // indirect
	google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd // indirect
	google.golang.org/grpc v1.47.0 // indirect
	google.golang.org/protobuf v1.28.0 // indirect
	gopkg.in/yaml.v2 v2.4.0 // indirect
	gopkg.in/yaml.v3 v3.0.1 // indirect
)
➜  ioc go run .
github.com/alibaba/ioc-golang/extension/aop/watch
../../../go/pkg/mod/github.com/alibaba/ioc-golang/[email protected]/aop/watch/interceptor.go:80:45: not enough arguments in call to common.ReflectValues2Strings
	have ([]reflect.Value)
	want ([]reflect.Value, int)
../../../go/pkg/mod/github.com/alibaba/ioc-golang/[email protected]/aop/watch/interceptor.go:81:45: not enough arguments in call to common.ReflectValues2Strings
	have ([]reflect.Value)
	want ([]reflect.Value, int)
github.com/alibaba/ioc-golang/extension/aop/transaction
../../../go/pkg/mod/github.com/alibaba/ioc-golang/[email protected]/aop/transaction/interceptor.go:51:78: not enough arguments in call to common.CurrentCallingMethodName
	have ()
	want (int)
github.com/alibaba/ioc-golang/extension/aop/trace
../../../go/pkg/mod/github.com/alibaba/ioc-golang/[email protected]/aop/trace/goroutine.go:21:89: not enough arguments in call to common.CurrentCallingMethodName
	have ()
	want (int)
../../../go/pkg/mod/github.com/alibaba/ioc-golang/[email protected]/aop/trace/interceptor.go:40:69: not enough arguments in call to common.CurrentCallingMethodName
	have ()
	want (int)

[Bug] RPC client would throw error when setting 'localhost:2022' to tag value.

As for a RPC Client injection:

// +ioc:autowire=true
// +ioc:autowire:type=singleton

type App struct {
	ServiceStruct api.ServiceStructIOCRPCClient `rpc-client:",address=127.0.0.1:2022"` // localhost:2022 would cause error 
}

error message is property [autowire rpc-client github.com/alibaba/ioc-golang/example/transaction_rpc/server/pkg/service/api.BankServiceIOCRPCClient param]'s key autowire not found, because the 'localhost' str is parsed failed.

[BUG] Proxy AOP layer returns reference value but not copy of value.

With param like slice: []string , Here is an example:

// input is []string{"hello")
func (i *Impl) Write(input []string){
    input.append(input, "world")
}

The watch values would shows the final value of the param: []string{"hello", "world", but not the real param value []string{"hello"}

[Enhancement] Split the gomod of the project root path to submodule.

After this period of observation and discussion with developer. I decided to split the go.mod files from the root directory into subdirectories to keep the root directory with minimal dependencies.

Before:

module github.com/alibaba/ioc-golang

go 1.17

require (
	dubbo.apache.org/dubbo-go/v3 v3.0.1
	github.com/apache/rocketmq-client-go/v2 v2.1.0
	github.com/cinience/go_rocketmq v0.0.2
	github.com/davecgh/go-spew v1.1.1
	github.com/fatih/color v1.13.0
	github.com/gin-gonic/gin v1.8.1
	github.com/glory-go/monkey v1.0.3-0.20220504040844-8c1fa6535179
	github.com/go-redis/redis v6.15.9+incompatible
	github.com/nacos-group/nacos-sdk-go/v2 v2.0.3
	github.com/opentracing/opentracing-go v1.2.0
	github.com/petermattis/goid v0.0.0-20220526132513-07eaf5d0b9f4
	github.com/pkg/errors v0.9.1
	github.com/spf13/cobra v1.4.0
	github.com/stretchr/testify v1.7.1
	github.com/uber/jaeger-client-go v2.29.1+incompatible
	google.golang.org/grpc v1.44.0
	google.golang.org/protobuf v1.28.0
	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
	gorm.io/driver/mysql v1.3.3
	gorm.io/gorm v1.23.5
	sigs.k8s.io/controller-tools v0.8.0
        github.com/gobuffalo/packr/v2 v2.8.3
)

require (
	github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
	github.com/Workiva/go-datastructures v1.0.52 // indirect
	github.com/aliyun/alibaba-cloud-sdk-go v1.61.18 // indirect
	github.com/aliyunmq/mq-http-go-sdk v1.0.3 // indirect
	github.com/andybalholm/brotli v1.0.0 // indirect
	github.com/apache/dubbo-getty v1.4.7 // indirect
	github.com/apache/dubbo-go-hessian2 v1.11.0 // indirect
	github.com/apache/rocketmq-client-go v1.2.5 // indirect
	github.com/beorn7/perks v1.0.1 // indirect
	github.com/buger/jsonparser v1.1.1 // indirect
	github.com/cespare/xxhash/v2 v2.1.2 // indirect
	github.com/dubbogo/gost v1.11.22 // indirect
	github.com/emirpasic/gods v1.12.0 // indirect
	github.com/gin-contrib/sse v0.1.0 // indirect
	github.com/go-errors/errors v1.0.1 // indirect
	github.com/go-ole/go-ole v1.2.4 // indirect
	github.com/go-playground/locales v0.14.0 // indirect
	github.com/go-playground/universal-translator v0.18.0 // indirect
	github.com/go-playground/validator/v10 v10.11.0 // indirect
	github.com/go-sql-driver/mysql v1.6.0 // indirect
	github.com/gobuffalo/logger v1.0.6 // indirect
	github.com/gobuffalo/packd v1.0.1 // indirect
	github.com/goccy/go-json v0.9.7 // indirect
	github.com/gogap/errors v0.0.0-20200228125012-531a6449b28c // indirect
	github.com/gogap/stack v0.0.0-20150131034635-fef68dddd4f8 // indirect
	github.com/golang/mock v1.5.0 // indirect
	github.com/golang/protobuf v1.5.2 // indirect
	github.com/golang/snappy v0.0.4 // indirect
	github.com/gorilla/websocket v1.5.0 // indirect
	github.com/inconshreveable/mousetrap v1.0.0 // indirect
	github.com/jinzhu/copier v0.3.5 // indirect
	github.com/jinzhu/inflection v1.0.0 // indirect
	github.com/jinzhu/now v1.1.4 // indirect
	github.com/jmespath/go-jmespath v0.4.0 // indirect
	github.com/json-iterator/go v1.1.12 // indirect
	github.com/k0kubun/pp v3.0.1+incompatible // indirect
	github.com/karrick/godirwalk v1.16.1 // indirect
	github.com/klauspost/compress v1.10.7 // indirect
	github.com/leodido/go-urn v1.2.1 // indirect
	github.com/markbates/errx v1.1.0 // indirect
	github.com/markbates/oncer v1.0.0 // indirect
	github.com/markbates/safe v1.0.1 // indirect
	github.com/mattn/go-colorable v0.1.9 // indirect
	github.com/mattn/go-isatty v0.0.14 // indirect
	github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
	github.com/modern-go/reflect2 v1.0.2 // indirect
	github.com/natefinch/lumberjack v2.0.0+incompatible // indirect
	github.com/pelletier/go-toml/v2 v2.0.1 // indirect
	github.com/pmezard/go-difflib v1.0.0 // indirect
	github.com/prometheus/client_golang v1.12.1 // indirect
	github.com/prometheus/client_model v0.2.0 // indirect
	github.com/prometheus/common v0.32.1 // indirect
	github.com/prometheus/procfs v0.7.3 // indirect
	github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b // indirect
	github.com/shirou/gopsutil v3.20.11+incompatible // indirect
	github.com/sirupsen/logrus v1.8.1 // indirect
	github.com/spf13/pflag v1.0.5 // indirect
	github.com/stretchr/objx v0.1.1 // indirect
	github.com/tidwall/gjson v1.2.1 // indirect
	github.com/tidwall/match v1.0.1 // indirect
	github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65 // indirect
	github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
	github.com/ugorji/go/codec v1.2.7 // indirect
	github.com/valyala/bytebufferpool v1.0.0 // indirect
	github.com/valyala/fasthttp v1.21.0 // indirect
	go.uber.org/atomic v1.9.0 // indirect
	go.uber.org/multierr v1.6.0 // indirect
	go.uber.org/zap v1.21.0 // indirect
	golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
	golang.org/x/mod v0.4.2 // indirect
	golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
	golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
	golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
	golang.org/x/text v0.3.7 // indirect
	golang.org/x/tools v0.1.7 // indirect
	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
	google.golang.org/genproto v0.0.0-20211104193956-4c6863e31247 // indirect
	gopkg.in/ini.v1 v1.62.0 // indirect
	gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
	gopkg.in/yaml.v2 v2.4.0 // indirect
	sigs.k8s.io/yaml v1.3.0 // indirect
	stathat.com/c/consistent v1.0.0 // indirect
)

After:

module github.com/alibaba/ioc-golang

go 1.17

require (
	github.com/davecgh/go-spew v1.1.1
	github.com/fatih/color v1.13.0
	github.com/glory-go/monkey v1.0.3
	github.com/opentracing/opentracing-go v1.2.0
	github.com/petermattis/goid v0.0.0-20220526132513-07eaf5d0b9f4
	github.com/pkg/errors v0.9.1
	github.com/stretchr/testify v1.7.5
	github.com/uber/jaeger-client-go v2.30.0+incompatible
	google.golang.org/grpc v1.47.0
	google.golang.org/protobuf v1.28.0
	gopkg.in/yaml.v3 v3.0.1
)

require (
	github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect
	github.com/golang/protobuf v1.5.2 // indirect
	github.com/mattn/go-colorable v0.1.9 // indirect
	github.com/mattn/go-isatty v0.0.14 // indirect
	github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
	github.com/pmezard/go-difflib v1.0.0 // indirect
	github.com/stretchr/objx v0.4.0 // indirect
	github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
	go.uber.org/atomic v1.7.0 // indirect
	golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
	golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect
	golang.org/x/text v0.3.7 // indirect
	google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect
	gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
)


Although, as before, packages in gomod does not represent packages pulled by the developer, the developer-side-project does not pull dependencies that have not been imported. What I should do is to make framework dependencies clearer and less misleading to developers.

Thanks for the issue #40

[Proposal] Add init command of iocli

Add 'init' command for iocli, to help developers generate application template.
The template should have following structure:

.
├── cmd
│   └── main.go
├── conf
│   └── ioc_golang.yaml
└── go.mod

main.go:

package main

import (
	"fmt"
	"github.com/alibaba/ioc-golang"
	"github.com/alibaba/ioc-golang/autowire/singleton"
)

// +ioc:autowire=true
// +ioc:autowire:type=singleton

type App struct {
}

func (a *App) Run() {
	fmt.Println("Hello world")
}

func main() {
	if err := ioc.Load(); err != nil {
		panic(err)
	}

	// We can get objects by ths id '$(PkgName).$(StructName)'
	appInterface, err := singleton.GetImpl("main.App")
	if err != nil {
		panic(err)
	}
	app := appInterface.(*App)
	app.Run()
}

ioc_golang.yaml

autowire:
  singleton:
    main.App:
      param:

[BUG] iocli relative replace bug causing go install failed.

replace statement in https://github.com/alibaba/IOC-golang/blob/master/iocli/go.mod#L40 cause error when running go install
error message is

go: github.com/alibaba/ioc-golang/iocli@master (in github.com/alibaba/ioc-golang/[email protected]):
        The go.mod file for the module providing named packages contains one or
        more replace directives. It must not contain directives that would cause
        it to be interpreted differently than if it were the main module.

[Proposal] RPC support with ioc-golang

As a Go application framework, we should provide RPC capability in microservice scenarios.Developers can specify some go structs with exported method (Upper character start) as RPC providers. After starting the application process, other applications in the same network space can call the methods of the current structure in the form of RPC.

  • Provider Side

The RPC service provider needs to add annotations for the structure that is expected to expose the service:

// +ioc:autowire:type=rpc

An example:

// +ioc:autowire=true
// +ioc:autowire:type=rpc

type ServiceStruct struct {
}

func (s *ServiceStruct) GetUser(name string, age int) (*dto.User, error) {
	return &dto.User{
		Id:   1,
		Name: name,
		Age:  age,
	}, nil
}

Then use a code generation tool
sudo iocli gen

The api/ folder will be created in the struct defined directory, which contains the stubs that the client needs to import. Client stub struct is named as $(structName)IOCRPCClient like ServiceStructIOCRPCClient

├── api
│   └── zz_generated.ioc_rpc_client_servicestruct.go
├── service.go
└── zz_generated.ioc.go
  • Client Side

Get client by dependency Injection, with tag rpc-client and param address, which points to provider's address, default port is 2022

ATTENTION, tag values contains ',' which is needed ,because tag format of ioc-golang is $(tagKey):"$(implStructSDID),$(param)", as for struct pointer injection, $(implStructSDID) can be readed from fieid type, so it is omited, and ',' should be preserved. the total tag value is ",address=127.0.0.1:2022"

An examples:

type App struct {
	ServiceStruct *api.ServiceStructIOCRPCClient `rpc-client:",address=127.0.0.1:2022"`
}

[Proposal] iocli tools support generate 'Get' method with specific type.

For example, with struct and marks below:

// +ioc:autowire=true
// +ioc:autowire:type=singleton

type App struct {}

As for iocli, in addition to generate struct descriptor, it also need to generate get function with specific type.

func GetApp() (*App, error){
     impl, err := singleton.GetImpl("main.App")
     if err != nil{
         return nil, err
    }
     return impl.(*App), err
}

[Feature] Multi autowire code generation support

Now we only support one type of autowire like 'singleton'

We should support multi autowire type code generation. To let struct user to descide which autowire type to use.
Take mysql orm as an example:
GORM provider can provide struct with two autowire type: singleton and normal, marked with // +ioc:autowire:type=normal,singleton, multi-autowire types are splited by ','

// +ioc:autowire=true
// +ioc:autowire:type=normal,singleton
// +ioc:autowire:paramType=Config
// +ioc:autowire:constructFunc=New

type GORMDB struct {
	db *gorm.DB
}

func (g*GORMDB) GetDB()*gorm.DB{
    return g.db
}

The genrated code should contains both autowire type releated codes:

func init(){
        // normal struct descriptor registry
    	normal.RegisterStructDescriptor(&autowire.StructDescriptor{
		Factory: func() interface{} {
			return &GORMDB{}
		},
	})
       // singleton struct descriptor registry
      singleton.RegisterStructDescriptor(&autowire.StructDescriptor{
		Factory: func() interface{} {
			return &GORMDB{}
		},
	})
}

// singleton struct Get API
func GetSingletonGORMDB() *GORMDB{
    	i, err := singleton.GetImpl(util.GetSDIDByStructPtr(new(GORMDB)), nil)
	if err != nil {
		return nil, err
	}
	impl := i.(*GORMDB)
	return impl, nil
}

// normal Get API
func GetNormalGORMDB() *GORMDB{
    	i, err := normal.GetImpl(util.GetSDIDByStructPtr(new(GORMDB)), nil)
	if err != nil {
		return nil, err
	}
	impl := i.(*GORMDB)
	return impl, nil
}

// singleton Get Interface API
func GetSingletonGORMDBIOCInterface(p *Config) (GORMDBIOCInterface, error) {
	i, err := singleton.GetImplWithProxy(util.GetSDIDByStructPtr(new(GORMDB)), p)
	if err != nil {
		return nil, err
	}
	impl := i.(GORMDBIOCInterface)
	return impl, nil
}
// normal Get Interface API
func GetNormalGORMDBIOCInterface(p *Config) (GORMDBIOCInterface, error) {
	i, err := normal.GetImplWithProxy(util.GetSDIDByStructPtr(new(GORMDB)), p)
	if err != nil {
		return nil, err
	}
	impl := i.(GORMDBIOCInterface)
	return impl, nil
}

[Proposal] Add Config Load Options

I Suggest to add load option for config.Load() method, as there should be param passing to config load procedure, like relative path.

I think options should be :

type LoadConfig struct {
	relativeConfigPath string
}

type LoadOption func(loadConfig *LoadConfig){}

func WithRelativeConfigPath(relativeConfigPath string) LoadOption{
	return func(loadConfig *LoadConfig) {
		loadConfig.relativeConfigPath = relativeConfigPath
	}
}

func init(){
	Load(WithRelativeConfigPath("./test/ioc_golang.yaml"))
}

func Load(opts ...LoadOption) error {
	cfg := &LoadConfig{}
	for _, opt := range opts{
		opt(cfg)
	}
        // load procedure
}

[Proposal] Add function signature constrain of transaction rollback function

Just like construct function constrain generated in zz_generated.ioc.go:

// construct function constrain type
type BankServiceConstructFunc func(impl *BankService) (*BankService, error)

// limit the function signature of construction function
var constructFunc BankServiceConstructFunc = InitBankService

We should add constrain type of transaction rollback function, to limit the rollback signature. As for the following transaction/rollback function pairs

// +ioc:autowire=true
// +ioc:autowire:type=rpc
// +ioc:tx:func=RemoveMoney-RemoveMoneyRollout

type BankService struct {
	Money map[int]int
}


func (b *BankService) RemoveMoney(id, num int) error {
	if num <= 0 {
		return fmt.Errorf("remove money num %d is not positive", num)
	}
	b.Money[id] -= num
	return nil
}

func (b *BankService) RemoveMoneyRollout(id, num int, errMsg string) {
	b.Money[id] += num
	fmt.Printf("Transaction is failed, real cause is '%s'\nmethod BankService.RemoveMoney is rolling back, add num %d\n", errMsg, num)
}

We should generated the constrain codes:

type RemoveMoneyRolloutFunction func(id, num int, errMsg string)

var _ RemoveMoneyRolloutFunction = (&BankService{}).RemoveMoneyRollout

[Enhancement] Get struct descripotor ID in generated API function only once.

Now the generated Get API is :

func GetServiceStructIOCInterfaceSingleton() (ServiceStructIOCInterface, error) {
	i, err := singleton.GetImplWithProxy(util.GetSDIDByStructPtr(new(ServiceStruct)), nil)
	if err != nil {
		return nil, err
	}
	impl := i.(ServiceStructIOCInterface)
	return impl, nil
}

The util.GetSDIDByStructPtr and new struct procedure is called every time. The sdid should be cached, and not get by every calling.

[Fix] Rename debug example to 'debug with monkey' example

  • We should add debug example, to show list, watch, feature using debug layer, as showed in README.
  • The 'debug example' for now, is 'debug with monkey' example essentially. we should rename it and fix README and docs to make the differences of the two examples clearer.

[Enhancement] Use colors to distinguish the interfaces/methods of iocli list command.

Use colors to distinguish the interfaces/methods of iocli list command.
For example, blue indicates the ioc-golang origin extension interface and red indicates the user defined interface.

 % iocli list
github.com/alibaba/ioc-golang/extension/autowire/rpc/protocol/protocol_impl.IOCProtocol
[Export Invoke]

github.com/alibaba/ioc-golang/extension/db/gorm.GORMDB
[InstanceGet Updates Count Row Rows InstanceSet Unscoped Save Transaction RollbackTo Model Assign UpdateColumn Exec Not FirstOrCreate Begin Take Scan SavePoint WithContext Table Offset FirstOrInit Debug ToSQL Omit AutoMigrate SetupJoinTable Group Migrator Use CreateInBatches Set Or Commit UpdateColumns Pluck Get Preload Find Last Association Where Joins Attrs Raw FindInBatches Update ScanRows Rollback Clauses Having Scopes Distinct Select First Order Limit Error Create Delete Session AddError DB Connection]

github.com/ioc-golang/shopping-system/pkg/service/product.Service
[GetRecommendProductIDs]

[Proposal] Design of tracing example and tasks.

  1. We should add an example 'tracing' to show the feature of 'whole calling stacks' tracing by open-tracing protocol.
  2. We should add an task to docs, to show how to troubleshoot time-cost problems based on a real-scene example of E-commerce scenario.
  3. We can explore a tracing capability based on iocli trace command, without using third-party collection server such as Jaeger, and support full-link real-time tracing capability through RPC protocol and Debug AOP layer.

iocli gen问题

type Test interface {
T(a int) (int64, []*int, error)
}

// +ioc:autowire=true
// +ioc:autowire:type=singleton
type TestImpl1 struct {
}

func (t *TestImpl1) T(a int) (int64, []*int, error) {
return 0, nil, nil
}

// +ioc:autowire=true
// +ioc:autowire:type=singleton
type TestImpl2 struct {
}

func (t *TestImpl2) T(a int) (int64, []*int, error) {
return 0, nil, nil
}

// +ioc:autowire=true
// +ioc:autowire:type=singleton
type TestImpl3 struct {
}

func (t *TestImpl3) T(
a int,
) (int64, []*int, error) {
return 0, nil, nil
}

使用 iocli gen后的zz_generated.ioc.go文件,如下:

//go:build !ignore_autogenerated
// +build !ignore_autogenerated

// Code generated by iocli, run 'iocli gen' to re-generate

package main

import (
autowire "github.com/alibaba/ioc-golang/autowire"
normal "github.com/alibaba/ioc-golang/autowire/normal"
singleton "github.com/alibaba/ioc-golang/autowire/singleton"
util "github.com/alibaba/ioc-golang/autowire/util"
)

func init() {
normal.RegisterStructDescriptor(&autowire.StructDescriptor{
Factory: func() interface{} {
return &testImpl1_{}
},
})
singleton.RegisterStructDescriptor(&autowire.StructDescriptor{
Factory: func() interface{} {
return &TestImpl1{}
},
})
normal.RegisterStructDescriptor(&autowire.StructDescriptor{
Factory: func() interface{} {
return &testImpl2_{}
},
})
singleton.RegisterStructDescriptor(&autowire.StructDescriptor{
Factory: func() interface{} {
return &TestImpl2{}
},
})
normal.RegisterStructDescriptor(&autowire.StructDescriptor{
Factory: func() interface{} {
return &testImpl3_{}
},
})
singleton.RegisterStructDescriptor(&autowire.StructDescriptor{
Factory: func() interface{} {
return &TestImpl3{}
},
})
}

type testImpl1_ struct {
T_ func(a int) (int64, []*int, error)
}

func (t *testImpl1_) T(a int) (int64, []*int, error) {
return t.T_(a)
}

type testImpl2_ struct {
T_ func(a int) (int64, []*int, error)
}

func (t *testImpl2_) T(a int) (int64, []*int, error) {
return t.T_(a)
}

type testImpl3_ struct {
}

type TestImpl1IOCInterface interface {
T(a int) (int64, []*int, error)
}

type TestImpl2IOCInterface interface {
T(a int) (int64, []*int, error)
}

type TestImpl3IOCInterface interface {
}

func GetTestImpl1() (*TestImpl1, error) {
i, err := singleton.GetImpl(util.GetSDIDByStructPtr(new(TestImpl1)), nil)
if err != nil {
return nil, err
}
impl := i.(*TestImpl1)
return impl, nil
}

func GetTestImpl1IOCInterface() (TestImpl1IOCInterface, error) {
i, err := singleton.GetImplWithProxy(util.GetSDIDByStructPtr(new(TestImpl1)), nil)
if err != nil {
return nil, err
}
impl := i.(TestImpl1IOCInterface)
return impl, nil
}

func GetTestImpl2() (*TestImpl2, error) {
i, err := singleton.GetImpl(util.GetSDIDByStructPtr(new(TestImpl2)), nil)
if err != nil {
return nil, err
}
impl := i.(*TestImpl2)
return impl, nil
}

func GetTestImpl2IOCInterface() (TestImpl2IOCInterface, error) {
i, err := singleton.GetImplWithProxy(util.GetSDIDByStructPtr(new(TestImpl2)), nil)
if err != nil {
return nil, err
}
impl := i.(TestImpl2IOCInterface)
return impl, nil
}

func GetTestImpl3() (*TestImpl3, error) {
i, err := singleton.GetImpl(util.GetSDIDByStructPtr(new(TestImpl3)), nil)
if err != nil {
return nil, err
}
impl := i.(*TestImpl3)
return impl, nil
}

func GetTestImpl3IOCInterface() (TestImpl3IOCInterface, error) {
i, err := singleton.GetImplWithProxy(util.GetSDIDByStructPtr(new(TestImpl3)), nil)
if err != nil {
return nil, err
}
impl := i.(TestImpl3IOCInterface)
return impl, nil
}

问题:
TestImpl3未正确生成对应函数签名,结果为空结构体。

[Proposal] mDNS support for ioc-rpc

I think we should support interface-based service discovery, to omited tag value address=127.0.0.1:2022.
We can setup mDNS to support this.

After that, client side should be written as below. And client side developers would not cares about providers. Unless he needs to customize some configuration, such as timeouts, load balancing, etc.

type App struct {
	ServiceStruct *api.ServiceStructIOCRPCClient `rpc-client:""`
}

What's more, the error-handle of failed discovery should be considered.

[Bug] iocli install error in windows platform

For windows platform , following error would occurs:

$ go install github.com/alibaba/ioc-golang/iocli@latest
undefined: syscall.SIGSTOP
undefined: syscall.SIGSYS

We should remove platform binding signals in extension/aop/monitor/cli/monitor.go

[Enhancement] Add constructFunc=init support to make construct function more clear.

Now our construction function's mark is like:

// +ioc:autowire=true
// +ioc:autowire:type=normal
// +ioc:autowire:paramType=Param
// +ioc:autowire:constructFunc=Init

Param.Init() is registered as construct function. But sometime there is no need for param, developers can use a simple function to create object like.

func constructFunction(impl *MyObject)(*MyObject,error){
    impl.ID = "xxx"
    return impl, nil
}

We should support both marks:

// +ioc:autowire:paramType=Param
// +ioc:autowire:constructFunc=Init
// to use Param.Init() as construct function with loaded params.

// +ioc:autowire:constructFunc=myConstructFunction
// to use myConstructFunction() as construct function.

[Proposal] Change example's project struct

  1. Rename 'debug' folder to 'aop'
  2. Refactor example/ folder project struct from tile style to group by example type, like 'autowire' 'aop' 'third_party' 'helloworld' 'config_file'.

[Feature] Add environment support in config file and tag param

Add read from env support marked by ${ENV} for config and tag param

A read-from-env config file example is

autowire:
  normal:
    github.com/alibaba/ioc-golang/extension/normal/mysql.GORMDB:
      dev-mysql:
        param:
          host: ${MYSQL_DB_HOST}
          port: ${MYSQL_DB_PORT}
          username: ${MYSQL_DB_NAME}
          password: ${MYSQL_DB_PASSWORD}
          dbname: "dev"

A tag param config env injection example is

FestivalServiceClient api.ServiceIOCRPCClient `rpc-client:",address=${FESTIVAL_RPC_SERVICE_ADDRESS}"`

[Proposal] Merge all gomod into one in root of package.

During this period of practice, multiple go mod files were placed in sub-directories respectively, which can indeed alleviate the problem of excessive dependency information of a single go mod. However, it caused the problem of incompatible versions of multiple modules, and when trying to tag, the dependent packages could not be guaranteed to be compatible. Tags cannot be updated at the same time they are tagged.
After thinking and designing, I decided to combine several go mod files into the same package, keeping the original design.
This makes no difference from the developer's point of view. There is no change to the API. I will label this change as 1.0.0-rc2

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.