.

.

扩展 autowire 模型

1 - 配置注入

简介

本示例展示了从配置文件注入字段的能力。

在应用开发过程中,从配置文件中读入配置是一个常见的诉求。例如读取数据库的账号密码、下游服务的主机名,以及一些业务配置等。

ioc-golang 框架提供了便捷的基于文件注入配置的能力,使开发者无需手动解析配置文件,无需手动组装对象。

注入模型与结构

config 依赖注入模型

关键代码:

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

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

type App struct {
	DemoConfigString *config.ConfigString `config:",autowire.config.demo-config.string-value"`
	DemoConfigInt    *config.ConfigInt    `config:",autowire.config.demo-config.int-value"`
	DemoConfigMap    *config.ConfigMap    `config:",autowire.config.demo-config.map-value"`
	DemoConfigSlice  *config.ConfigSlice  `config:",autowire.config.demo-config.slice-value"`
}
  • 被注入字段类型

    目前支持 ConfigString,ConfigInt,ConfigMap,ConfigSlice 四种类型。

    需要以 指针 的形式声明字段类型

  • 标签与注入位置

    开发人员可以给结构增加 ``config:",xxx" 标签, 标注需要注入的值类型,以及该字段位于配置文件的位置。

    例子中的

    config:",autowire.config.demo-config.string-value"

    的意义为,将配置文件内 autowire.config.demo-config.string-value 的值注入到该字段。

    对应配置文件:ioc_golang.yaml 中的字符串 “stringValue”

    autowire:
      config:
        demo-config:
          int-value: 123
          int64-value: 130117537261158665
          float64-value: 0.001
          string-value: stringValue
          map-value:
            key1: value1
            key2: value2
            key3: value3
            obj:
              objkey1: objvalue1
              objkey2: objvalue2
              objkeyslice: objslicevalue
          slice-value:
            - sliceValue1
            - sliceValue2
            - sliceValue3
            - sliceValue4
    

运行示例

cd example/autowire_config/cmd
go run .
  ___    ___     ____            ____           _                         
 |_ _|  / _ \   / ___|          / ___|   ___   | |   __ _   _ __     __ _ 
  | |  | | | | | |      _____  | |  _   / _ \  | |  / _` | | '_ \   / _` |
  | |  | |_| | | |___  |_____| | |_| | | (_) | | | | (_| | | | | | | (_| |
 |___|  \___/   \____|          \____|  \___/  |_|  \__,_| |_| |_|  \__, |
                                                                    |___/ 
Welcome to use ioc-golang!
[Boot] Start to load ioc-golang config
[Config] merge config map, depth: [0]
[Boot] Start to load debug
[Debug] Debug mod is not enabled
[Boot] Start to load autowire
[Autowire Type] Found registered autowire type singleton
[Autowire Struct Descriptor] Found type singleton registered SD main.App
[Autowire Type] Found registered autowire type normal
[Autowire Type] Found registered autowire type config
[Autowire Struct Descriptor] Found type config registered SD github.com/alibaba/ioc-golang/extension/config.ConfigInt64
[Autowire Struct Descriptor] Found type config registered SD github.com/alibaba/ioc-golang/extension/config.ConfigInt
[Autowire Struct Descriptor] Found type config registered SD github.com/alibaba/ioc-golang/extension/config.ConfigMap
[Autowire Struct Descriptor] Found type config registered SD github.com/alibaba/ioc-golang/extension/config.ConfigSlice
[Autowire Struct Descriptor] Found type config registered SD github.com/alibaba/ioc-golang/extension/config.ConfigString
[Autowire Struct Descriptor] Found type config registered SD github.com/alibaba/ioc-golang/extension/config.ConfigFloat64
2022/06/06 18:01:22 load config path autowire.config#demo-config#float64-value error =  property [autowire config#demo-config#float64-value]'s key config#demo-config#float64-value not found
stringValue
123
map[key1:value1 key2:value2 key3:value3 obj:map[objkey1:objvalue1 objkey2:objvalue2 objkeyslice:objslicevalue]]
[sliceValue1 sliceValue2 sliceValue3 sliceValue4]
130117537261158665
0
stringValue
123
map[key1:value1 key2:value2 key3:value3 obj:map[objkey1:objvalue1 objkey2:objvalue2 objkeyslice:objslicevalue]]
[sliceValue1 sliceValue2 sliceValue3 sliceValue4]
130117537261158665
0

可看到依次打印出了不同结构的注入配置。

2 - RPC 能力

使用 RPC 能力

简介

本示例展示了基于 IOC-golang 框架的 RPC 能力

在微服务开发过程中,暴露一些对象的方法给外部程序调用是一种常见的场景。

在 IOC-golang 的 RPC 能力的使用场景下,客户端可以直接注入下游接口的客户端存根,以方法调用的形式发起RPC请求。

关键代码

服务端

需要暴露的RPC服务结构使用 // +ioc:autowire:type=rpc 标注,例如 service.go:

import (
	"github.com/alibaba/ioc-golang/example/autowire_rpc/server/pkg/dto"
)

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

使用 iocli 工具生成相关代码。

sudo iocli gen

% tree
.
├── api
│   └── zz_generated.ioc_rpc_client_servicestruct.go
├── service.go
└── zz_generated.ioc.go

会在当前文件目录下生成 zz_generated.ioc.go 包含了服务提供者的结构描述信息。也会在当前目录下创建 api/ 文件夹,并创建当前结构的客户端存根文件 zz_generated.ioc_rpc_client_servicestruct.go

客户端

可以通过标签注入的方法,注入客户端存根,存根中给出下游地址。默认服务暴露端口为2022

import(
  "github.com/alibaba/ioc-golang/example/autowire_rpc/server/pkg/service/api"
)
// +ioc:autowire=true
// +ioc:autowire:type=singleton

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

func (a *App) Run() {
	for {
		time.Sleep(time.Second * 3)
		usr, err := a.ServiceStruct.GetUser("laurence", 23) // RPC调用
		if err != nil {
			panic(err)
		}
		fmt.Printf("get user = %+v\n", usr)
	}
}

运行示例

启动服务端

服务端需要确保引入对应服务提供者结构包: _ "github.com/alibaba/ioc-golang/example/autowire_rpc/server/pkg/service"

package main

import (
	"github.com/alibaba/ioc-golang"
	_ "github.com/alibaba/ioc-golang/example/autowire_rpc/server/pkg/service"
)

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

启动服务端进程,默认 rpc 服务监听 2022 端口

% cd server
% go run .
...
[negroni] listening on :2022

启动客户端

开启另一个终端,进入client目录,启动进程,不断发起调用,获得返回值。

% cd client
% go run .
...
get user = &{Id:1 Name:laurence Age:23}
get user = &{Id:1 Name:laurence Age:23}
get user = &{Id:1 Name:laurence Age:23}

3 - gRPC 客户端注入

简介

本示例展示了基于 ioc-golang 框架的 gRPC 客户端注入能力。

在进行微服务开发过程中,服务间通信尤为重要,gRPC 是被应用最为广泛的 RPC 框架之一。

在常规开发中,开发者需要从配置中手动读取下游主机名,启动 grpc 客户端。针对一个接口的网络客户端往往是单例模型,如果多个服务都需要使用同一客户端,则还需要开发者维护这个单例模型。

基于 ioc-golang 框架的 gRPC 客户端注入能力,我们可以将客户端的生命周期交付给框架管理,并赋予客户端调试能力,开发者只需要关注注册和使用。

示例介绍

本示例实现了以下拓扑

debug

在这个例子中,App 结构会依此调用所有依赖对象,进而调用一个单例模型注入的 gRPC 客户端,该客户端发起网络请求,并获得结果。

依赖注入模型

grpc 依赖注入模型

关键代码

import(
  "github.com/alibaba/ioc-golang/extension/autowire/grpc"
	googleGRPC "google.golang.org/grpc"
)
func init() {
	// register grpc client
	grpc.RegisterStructDescriptor(&autowire.StructDescriptor{
		Interface: new(api.HelloServiceClient),
		Factory: func() interface{} {
			return new(api.HelloServiceClient)
		},
		ParamFactory: func() interface{} {
			return &googleGRPC.ClientConn{}
		},
		ConstructFunc: func(impl interface{}, param interface{}) (interface{}, error) {
			conn := param.(*googleGRPC.ClientConn)
			fmt.Println("create conn target ", conn.Target())
			return api.NewHelloServiceClient(conn), nil
		},
	})
}

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

type App struct {
	HelloServiceClient api.HelloServiceClient `grpc:"hello-service"`
}

需要在代码中手动注册 gRPC 客户端。在需要使用的地方,增加 grpc:"xxx" 标签

框架会默认从 autowire.grpc.xxx 读取参数, 在例子中,为autowire.grpc.hello-service

autowire:
  grpc:
    hello-service:
      address: localhost:8080

运行示例

  1. 启动 grpc Server

    % cd example/denbug/grpc_server
    % go run .
    
  2. 新开一个终端,启动客户端。

    % cd example/autowire_grpc_client/cmd
    % go run .
      ___    ___     ____            ____           _                         
     |_ _|  / _ \   / ___|          / ___|   ___   | |   __ _   _ __     __ _ 
      | |  | | | | | |      _____  | |  _   / _ \  | |  / _` | | '_ \   / _` |
      | |  | |_| | | |___  |_____| | |_| | | (_) | | | | (_| | | | | | | (_| |
     |___|  \___/   \____|          \____|  \___/  |_|  \__,_| |_| |_|  \__, |
                                                                        |___/ 
    Welcome to use ioc-golang!
    [Boot] Start to load ioc-golang config
    [Config] Load config file from ../conf/ioc_golang.yaml
    [Boot] Start to load debug
    [Debug] Debug mod is not enabled
    [Boot] Start to load autowire
    [Autowire Type] Found registered autowire type grpc
    [Autowire Struct Descriptor] Found type grpc registered SD github.com/alibaba/ioc-golang/example/autowire_grpc_client/api.HelloServiceClient
    [Autowire Type] Found registered autowire type singleton
    [Autowire Struct Descriptor] Found type singleton registered SD github.com/alibaba/ioc-golang/example/autowire_grpc_client/cmd/struct1.Struct1
    [Autowire Struct Descriptor] Found type singleton registered SD main.App
    [Autowire Struct Descriptor] Found type singleton registered SD github.com/alibaba/ioc-golang/example/autowire_grpc_client/cmd/service1.Impl1
    [Autowire Struct Descriptor] Found type singleton registered SD github.com/alibaba/ioc-golang/example/autowire_grpc_client/cmd/service2.Impl1
    [Autowire Struct Descriptor] Found type singleton registered SD github.com/alibaba/ioc-golang/example/autowire_grpc_client/cmd/service2.Impl2
    create conn target  localhost:8080
    App call grpc get: Hello laurence
    ExampleService1Impl1 call grpc get :Hello laurence
    ExampleService2Impl1 call grpc get :Hello laurence_service2_impl1
    ExampleService2Impl2 call grpc get :Hello laurence_service2_impl2
    ExampleStruct1 call grpc get :Hello laurence_service1_impl1
    

小节

gRPC 客户端注入能力,所代表的是 ioc-golang 框架具备网络模型注入的能力。

针对特定网络框架,可以在其服务提供者接口处,提供客户端注入代码,从而便于客户端引入后直接注入。