Trpc插件机制

28 阅读3分钟

plugin 插件机制

概述

tRPC-Go 在设计上遵循了插件化架构理念,通过插件来实现框架核心与各种生态体系的对接,提供了框架的开放性和可扩展性

trpc-goplugin 包用于管理需要依赖配置进行加载的插件。

插件工厂采用了两级管理模式:

  • 插件类型,例如,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
}