Skip to content

Latest commit

 

History

History
362 lines (259 loc) · 11.6 KB

README_CN.md

File metadata and controls

362 lines (259 loc) · 11.6 KB

IOC-golang:一款 GO 语言依赖注入框架

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

IOC-golang CI License

English | 中文

demo gif

IOC-golang 是一款强大的 Go 语言依赖注入框架,提供了一套完善的 IoC 容器。其能力如下:

  • 依赖注入

    支持任何结构、接口的依赖注入,具备完善的对象生命周期管理机制。

    可以接管对象的创建、参数注入、工厂方法、参数来源等等,并拥有可扩展性。

  • 接口代理

    基于 AOP 的思路,为由框架接管的对象提供默认的接口代理层,在面向接口编程的情景下,可以在 业务无侵入 的前提下,使用基于结构代理 AOP 层扩展的丰富运维能力。例如接口查询,参数动态监听,方法粒度链路追踪,性能瓶颈分析,分布式场景下全链路方法粒度追踪等。

    • 监控
    • 日志采集
    • 链路追踪
    • 事务能力
  • 代码生成能力

    我们提供了代码生成工具,开发者可以通过注解的方式标注结构,从而便捷地生成结构注册代码、结构代理、结构专属接口等。

  • 可扩展能力

    支持被注入结构的扩展、自动装载模型的扩展、调试 AOP 层的扩展。

  • 丰富的预置组件

    提供覆盖主流中间件的预制对象,方便直接注入使用。

项目结构

  • aop: 结构代理 AOP 模块:提供 AOP 层的基础能力,和可扩展API。
  • autowire: 提供依赖注入内核,以及单例模型、多例模型两种基本自动装载模型
  • config: 配置加载模块,负责解析框架配置文件。
  • extension: 组件扩展:提供基于多个领域模型的的预置实现结构,比如缓存、数据库、消息。
  • example: 示例
  • iocli: 代码生成/程序调试 工具

快速开始

安装代码生成工具

% go install github.com/alibaba/ioc-golang/iocli@v1.0.3
% iocli
hello

依赖注入教程

我们将开发一个具有以下拓扑的工程,在本例子中,可以展示

  1. 注册代码生成
  2. 接口注入
  3. 对象指针注入
  4. API 获取对象
  5. 调试能力,查看运行中的接口、方法;以及实时监听参数值、返回值。

ioc-golang-quickstart-structure

用户所需编写的全部代码:main.go

package main

import (
	"fmt"
	"time"

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

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

type App struct {
	// 将封装了代理层的 main.ServiceImpl1 指针注入到 Service 接口,单例模型,需要在标签中指定被注入结构
	ServiceImpl1 Service `singleton:"main.ServiceImpl1"`

	// 将封装了代理层的 main.ServiceImpl2 指针注入到 Service 接口,单例模型,需要在标签中指定被注入结构
	ServiceImpl2 Service `singleton:"main.ServiceImpl2"`

	// 将封装了代理层的 main.ServiceImpl1 指针注入到它的专属接口 'ServiceImpl1IOCInterface'
  // 注入专属接口的命名规则是 '${结构名}IOCInterface',注入专属接口无需指定被注入结构,标签值为空即可。
	Service1OwnInterface ServiceImpl1IOCInterface `singleton:""`

	// 将结构体指针注入当前字段
	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() {
	// 加载所有结构
	if err := ioc.Load(); err != nil {
		panic(err)
	}

	// 获取结构
	app, err := GetAppSingleton()
	if err != nil {
		panic(err)
	}
	app.Run()
}

上述所说的“代理层”,是框架为“以接口形式注入/获取”的结构体,默认封装的代理,可以基于框架提供的 AOP 扩展能力,扩展一系列运维操作。我们推荐开发者在编写代码的过程中基于接口编程,则所有对象都可拥有运维能力。

编写完毕后,当前目录执行以下命令,初始化 go mod ,拉取最新代码,生成结构注册代码。(mac 环境可能因权限原因需要sudo):

% 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

会在当前目录生成:zz_generated.ioc.go,开发者无需关心这一文件,这一文件中就包含了上面使用的 GetAppSingleton 方法

//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
}

查看当前目录文件

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

0 directories, 4 files

执行程序

go run .

控制台打印输出:

  ___    ___     ____                           _                         
 |_ _|  / _ \   / ___|           __ _    ___   | |   __ _   _ __     __ _ 
  | |  | | | | | |      _____   / _` |  / _ \  | |  / _` | | '_ \   / _` |
  | |  | |_| | | |___  |_____| | (_| | | (_) | | | | (_| | | | | | | (_| |
 |___|  \___/   \____|          \__, |  \___/  |_|  \__,_| |_| |_|  \__, |
                                |___/                               |___/ 
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
...

可看到,依赖注入成功,程序正常运行。

调试程序

可看到打印出的日志中包含,说明 Debug 服务已经启动。

[Debug] Debug server listening at :1999

新开一个终端,使用 iocli 的调试功能,查看所有拥有代理层的结构和方法。默认端口为 1999。

% iocli list
main.ServiceImpl1
[GetHelloString]

main.ServiceImpl2
[GetHelloString]

监听方法的参数和返回值。以监听 main.ServiceImpl 结构的 GetHelloString 方法为例,每隔三秒钟,函数被调用两次,打印参数和返回值。

% 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"
,,,

注解分析

// +ioc:autowire=true
代码生成工具会识别到标有 +ioc:autowire=true 注解的对象

// +ioc:autowire:type=singleton
标记注入模型为 singleton 单例模型

更多

中文文档

更多代码生成注解可以移步iocli.查看。

可以移步 ioc-golang/example 查看更多例子

可以参考 基于 IOC-golang 的电商系统demo 查看分布式场景下的应用系统示例

如您在使用框架的过程中遇到问题,可以参考 常见问题诊断

证书

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

联系我们

感兴趣的开发者可以加入钉钉群:44638289

Star me please ⭐

如果你对这个项目本身或者实现思路感兴趣,可以给我们一颗 ⭐