plugin 插件机制
概述
tRPC-Go 在设计上遵循了插件化架构理念,通过插件来实现框架核心与各种生态体系的对接,提供了框架的开放性和可扩展性
trpc-go 下 plugin 包用于管理需要依赖配置进行加载的插件。
插件工厂采用了两级管理模式:
- 插件类型,例如,
log类型,conf类型,selector类型等。 - 插件名称,例如,
conf的插件有本地文件配置,远程文件配置,本地数据库配置等
对于插件的类型,plugin 包并没有做限制,你可以自行添加插件类型。
核心接口
所有插件都被注册在 trpc-go/plugin 包下的一张 map 中。
var plugins = make(map[string]map[string]Factory) // plugin type => { plugin name => plugin factory }
插件接口
// 插件工厂
// 定义插件的类型和初始化流程
type Factory interface {
// 插件类型
Type() string
// 插件初始化
// name为插件名称(如tconf),dec为包含trpc_go配置的解码器,用于解析插件配置
Setup(name string, dec Decoder) error
}
// 用于解析自定义插件配置的解码器(一般都是yaml)
type Decoder interface {
// 解析trpc_go文件内的插件配置到自定义结构体
Decode(cfg interface{}) error
}
事件回调接口
// 插件SetUp完成后回调接口
type FinishNotifier interface {
// name为插件名
OnFinish(name string) error
}
// 关闭接口, 用于在插件关闭前执行销毁流程(比如关闭连接/协程池等)
// trpc服务关闭的时候执行, 调用顺序是先初始化的后关闭
type Closer interface {
Close() error
}
插件依赖接口(实现原理是把所有要初始化的插件都放进一个 chan 里,然后遍历 chan,每次初始化一个插件就检查需要的依赖是否已完成初始化,否则就重新放入 chan 队尾)
// Depender 是 "强依赖" 的接口。
// 如果插件 a "强烈" 依赖插件 b,那么 b 必须存在,
// a 将在 b 初始化之后进行初始化。
type Depender interface {
// 依赖插件列表,格式"插件类型-插件名",如[ "selector-polaris" ]
// version >= 0.19.0下,支持"插件类型-*"代指这个类型所有插件,如["selector-*"]
DependsOn() []string
}
// FlexDepender 是 "弱依赖" 的接口。
// 如果插件 a "弱" 依赖插件 b,并且 b 确实存在,
// 那么 a 将在 b 初始化之后进行初始化。
type FlexDepender interface {
// 依赖插件列表,格式"插件类型-插件名",如[ "selector-polaris" ]
// version >= 0.19.0下,支持"插件类型-*"代指这个类型所有插件,如["selector-*"]
FlexDependsOn() []string
}
自定义插件案例
定义 trpc_go 文件插件配置
plugins:
helloPlugin: # 插件类型
myPlugins: # 插件名称
name: helloworld # 自定义配置
version: 1.0.0 # 自定义配置
定义插件逻辑
package plugin
import (
"fmt"
"trpc.group/trpc-go/trpc-go/plugin"
)
var (
name = "myPlugins"
typ = "helloPlugin"
)
func init() {
// 注册插件到 trpc 的插件容器里
plugin.Register(name, &MyPlugin{})
}
// MyPlugin 自定义插件
type MyPlugin struct{}
// Type 指定插件类型
func (plugin *MyPlugin) Type() string {
return typ
}
type config struct {
Name string `yaml:"name"`
Version string `yaml:"version"`
}
// Setup 插件初始化
func (plugin *MyPlugin) Setup(name string, dec plugin.Decoder) error {
// 读取 trpc_go 配置上的插件配置
c := config{}
err := dec.Decode(&c)
if err != nil {
return err
}
// 执行插件初始化操作
fmt.Println("Loading plugin", name, "version", c.Version)
// 需要放入可被外部获取的map或其他api包
// 例如:conf/registry等插件需要放入config.RegisterProvider/registry.Register
return nil
}
// Close 插件关闭
func (plugin *MyPlugin) Close() error {
// 关闭插件操作
fmt.Println("Closing plugin", name)
return nil
}
// OnFinish 插件初始化完成回调
func (plugin *MyPlugin) OnFinish(name string) error {
// 插件初始化完成后做操作
fmt.Println("OnFinish", name)
return nil
}