返回顶部
首页 > 资讯 > 后端开发 > GO >Golang库插件注册加载机制的问题
  • 473
分享到

Golang库插件注册加载机制的问题

2024-04-02 19:04:59 473人浏览 八月长安
摘要

目录注册加载总结最近看到一个内部项目的插件加载机制,非常赞。当然这里说的插件并不是指的golang原生的可以在buildmode中加载指定so文件的那种加载机制。而是软件设计上的「插

最近看到一个内部项目插件加载机制,非常赞。当然这里说的插件并不是指的golang原生的可以在buildmode中加载指定so文件的那种加载机制。而是软件设计上的「插件」。如果你的软件是一个框架,或者一个平台性产品,想要提升扩展性,即可以让第三方进行第三方库开发,最终能像搭积木一样将这些库组装起来。那么就可能需要这种库加载机制。

我们的目标是什么?对第三方库进行某种库规范,只要按照这种库规范进行开发,这个库就可以被加载到框架中。

我们先定义一个插件的数据结构,这里肯定是需要使用接口来规范,这个可以根据你的项目自由发挥,比如我希望插件有一个Setup方法来在启动的时候加载即可。然后我就定义如下的Plugin结构。

type Plugin interface{
  Name() string
  Setup(config map[string]string) error
}

而在框架启动的时候,我启动了一个如下的全局变量:

var plugins map[string]Plugin

注册

有人可能会问,这里有了加载函数setup,但是为什么没有注册逻辑呢?

答案是注册的逻辑放在库的init函数中。

即框架还提供了一个注册函数。

// package plugin
ReGISter(plugin Plugin)

这个register就是实现了将第三方plugin放到plugins全局变量中。

所以第三方的plugin库大致实现如下:

package MyPlugin

type MyPlugin struct{
}
func (m *MyPlugin) Setup(config map[string]string) error {
	// TODO
func (m *MyPlugin) Name() string {
	return "myPlugin"
func init() {
	plugin.Register(&MyPlugin)

这样注册的逻辑就变成了,如果你要加载一个插件,那么你在main.Go中直接以 _ import的形式引入即可。

package main

_ import "GitHub.com/foo/myplugin"
func main() {
}

整体的感觉,这样子插件的注册就被“隐藏”到import中了。

加载

注册的逻辑其实看起来也平平无奇,但是加载的逻辑就考验细节了。

首先插件的加载其实有两点需要考虑:

  • 配置
  • 依赖

配置指的是插件一定是有某种配置的,这些配置以配置文件yaml中plugins.myplugin的路径存在。

plugins:
	myplugin:
		foo: bar

其实我对这种实现持保留意见。配置文件以一个文件中配置项的形式存在,好像不如以配置文件的形式存在,即以config/plugins/myplugin.yaml 的文件。

这样不会出现一个大配置文件的问题。毕竟每个配置文件本身就是一门DSL语言。如果你将配置文件的逻辑变复杂,一定会有很多附带的bug是由于配置文件错误导致的。

第二个说的是依赖。插件A依赖与插件B,那么这里就有加载函数Setup的先后顺序了。这种先后顺序如果纯依赖用户的“经验”,将某个插件的Setup调用放在某个插件的Setup调用之前,是非常痛苦的。(虽然一定是有办法可以做到)。更好的办法是依赖于框架自身的加载机制来进行加载。

首先我们在plugin包中定义一个接口:

type Depend interface{
	DependOn() []string
}

如果我的插件依赖一个名字为 “fooPlugin” 的插件,那么我的插件 MyPlugin就会实现这个接口。

package MyPlugin

type MyPlugin struct{
}
func (m *MyPlugin) Setup(config map[string]string) error {
	// TODO
func (m *MyPlugin) Name() string {
	return "myPlugin"
func init() {
	plugin.Register(&MyPlugin)
func (m *MyPlugin) DependOn() []string {
	return []string{"fooPlugin"}

在最终加载所有插件的时候,我们并不是简单地将所有插件调用Setup,而是使用一个channel,将所有插件放在channel中,然后一个个调用Setup,遇到有Depend其他插件的,且依赖插件还未被加载,则将当前插件放在队列最后(重新塞入channel)。

var setupStatus map[string]bool

// 获取所有注册插件
func loadPlugins() (plugin chan Plugin, setupStatus map[string]bool) {
	// 这里定义一个长度为10的队列
	var sortPlugin = make(chan Plugin, 10)
	var setupStatus = make[string]bool
	
	// 所有的插件
	for name, plugin := range plugins {
		sortPlugin <- plugin
		setupStatus[name] = false
	}
	return sortPlugin, setupStatus
}
// 加载所有插件
func SetupPlugins(pluginChan chan Plugin, setupStatus map[string]bool) error {
	num := len(pluginChan)
	for num > 0 {
		plugin <- pluginChan
		
		canSetup := true
		if deps, ok := p.(Depend); ok {
			depends := deps.DependOn()
			for _, dependName := range depends{
				if _, setuped := setupStatus[dependName]; !setup {
						// 有未加载的插件
						canSetup = false
						break
				}
			}
		}
		// 如果这个插件能被setup
		if canSetup {
			plugin.Setup(xxx)
			setupStatus[p.Name()] = true
		} else {
			// 如果插件不能被setup, 这个plugin就塞入到最后一个队列
			pluginChan <- plugin
	return nil
} 

上面这段代码最精妙的就是使用了一个有buffer的channel作为一个队列,消费队列一方SetupPlugins,除了消费队列,也有可能生产数据到队列,这样就保证了队列中所有plugin都是被按照标记的依赖被顺序加载的。

总结

这种插件的注册和加载机制是非常优雅的。注册方面,巧妙使用隐式import来做插件的注册。而加载方面,巧妙使用有buffer的channel作为加载队列。

到此这篇关于Golang库插件注册加载机制的文章就介绍到这了,更多相关Golang插件机制内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

您可能感兴趣的文档:

--结束END--

本文标题: Golang库插件注册加载机制的问题

本文链接: https://lsjlt.com/news/144112.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Golang库插件注册加载机制的问题
    目录注册加载总结最近看到一个内部项目的插件加载机制,非常赞。当然这里说的插件并不是指的golang原生的可以在buildmode中加载指定so文件的那种加载机制。而是软件设计上的「插...
    99+
    2024-04-02
  • 如何解决Golang库插件注册加载机制的问题
    这篇文章主要介绍如何解决Golang库插件注册加载机制的问题,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!最近看到一个内部项目的插件加载机制,非常赞。当然这里说的插件并不是指的golang原生的可以在buildmod...
    99+
    2023-06-29
  • 配置java.library.path加载库文件问题
    目录配置java.library.path加载库文件实列一实列二java.library.path在哪?编译运行可得总结配置java.library.path加载库文件 本文将告诉你...
    99+
    2022-12-23
    配置java.library.path java.library.path java.library.path加载库文件
  • JDBC以反射机制加载类注册驱动连接MySQL
    package test.jdbc; //JDBC注册驱动的另一种方式:(这种方式常用) public class JDBC3 { public static void m...
    99+
    2024-04-02
  • AndroidWebView缓存机制优化加载慢问题
    目录一 、前言二 、WebView存在的性能问题2.1 H5 页面加载速度慢2.1.1 渲染速度慢2.1.2 页面资源加载缓慢2.2 耗费流量2.3 总结三 解决方案3.1 前端H5...
    99+
    2023-02-07
    Android WebView缓存机制 Android WebView
  • JDKSPI机制以及自定义SPI类加载问题
    目录概述规则自定义实现注解基于SPI的伪类加载器测试概述 介绍SPI之前,我们先了解一下为什么要用SPI JDBC相信已经不陌生了,JDBC 是一个标准。 不同的数据库厂商(如,my...
    99+
    2022-11-21
    JDK SPI机制 自定义SPI类加载 SPI类加载
  • 基于python脚本实现软件的注册功能(机器码+注册码机制)
    一、前言: 目的:完成已有python图像处理工具的注册功能 功能:用户运行程序后,通过文件自动检测认证状态,如果未经认证,就需要注册。注册过程是用户将程序运行后显示的机器码(C盘的卷序号)发回给管理员,管...
    99+
    2022-06-04
    机器码 注册码 脚本
  • SAP CRM的事件注册机制怎么实现
    本篇内容介绍了“SAP CRM的事件注册机制怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Subject: Agent inbox在...
    99+
    2023-06-04
  • 关于vue3编写挂载DOM的插件问题
    vue3 跟 vue2 相比,多了一个 app 的概念,vue3 项目的创建也变成了 // main.js import { createApp } from 'vue' imp...
    99+
    2024-04-02
  • 如何处理JVM类加载机制及类缓存问题
    这篇文章给大家分享的是有关如何处理JVM类加载机制及类缓存问题的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。前言大家应该都知道,当一个Java项目启动的时候,JVM会找到main方法,根据对象之间的调用来对cla...
    99+
    2023-05-30
  • SAP CRM One Order的事件注册机制是什么
    这期内容当中小编将会给大家带来有关SAP CRM One Order的事件注册机制是什么,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。有大量的函数模块作为事件回调在一个顺序的运行时中被调用。如果您想自己研...
    99+
    2023-06-04
  • 解决jupyter加载文件失败的问题
    遇到个小白常见的问题,发现度娘里面没有记录,翻墙谷歌了下,解决问题,在此写个说明。 事情起因: 在jupyter notebook中导入文件时发生了错误: %load p2_te...
    99+
    2024-04-02
  • springboot启动不加载bootstrap.yml文件的问题
    目录springboot启动不加载bootstrap.yml文件无法识别 bootstrap.yml 小绿叶问题错误信息问题定位解决springboot启动不加载bootstrap....
    99+
    2024-04-02
  • jquery touch事件注册不了的问题怎么解决
    今天小编给大家分享一下jquery touch事件注册不了的问题怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。随着移...
    99+
    2023-07-06
  • ElementUI中的日历组件加载无效的问题
      在ElementUI中提供了一个日历组件。在某些场景下还是比较有用的。只是在使用的时候会有些下坑,大家要注意下。   官网提供的信息比较简介。我们在引入到项目中使用的时候可以能会出现下面的错误提示。 Unknown custom e...
    99+
    2023-08-30
    elementui el-calendar 日历 不显示 组件 Vue
  • JVM加载class文件的原理机制是什么
    今天小编给大家分享一下JVM加载class文件的原理机制是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、JVM简介J...
    99+
    2023-06-30
  • 面试必时必问的JVM 类加载机制详解
    目录前言正文1、类加载的过程。1)加载2)验证3)准备4)解析5)初始化2、Java 虚拟机中有哪些类加载器?1)启动类加载器(Bootstrap ClassLoader):2)扩展...
    99+
    2024-04-02
  • Mybatis基于MapperScan注解的动态代理加载机制详解
    1.如下图在代码开发中使用mybatis时,通过一个接口UserDao对应的方法selectUserNameById执行xml里配置的selectUserNameById查...
    99+
    2023-01-28
    Mybatis动态代理加载 Mybatis MapperScan注解动态代理加载
  • JVM加载class文件的原理机制实例详解
    目录一、JVM简介二、JVM的组成部分三、JVM加载class文件的原理机制一、JVM简介 JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于...
    99+
    2024-04-02
  • 深入了解 Go 中的接口文件加载机制
    Go 语言中的接口文件加载机制是一项非常重要的功能,它允许用户在程序运行时动态加载接口文件,并且让程序更加灵活。在本文中,我们将,并通过演示代码来更好地理解它。 首先,我们需要知道,Go 语言中的接口文件加载机制是通过使用动态链接库(Dyn...
    99+
    2023-09-02
    接口 文件 load
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作