In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
This article mainly introduces how to solve the problem of Golang library plug-in registration loading mechanism, the article is very detailed, has a certain reference value, interested friends must read it!
Recently I saw a plug-in loading mechanism for an internal project, which is very good. Of course, the plug-in here does not refer to the golang native loading mechanism that can load specified so files in buildmode. It is a "plug-in" in software design. If your software is a framework, or a platform product, and you want to improve scalability, you can have third parties develop third-party libraries and eventually assemble them like building blocks. Then you may need this library loading mechanism.
What is our goal? Carry on some kind of library specification to the third-party library, as long as it is developed according to this library specification, the library can be loaded into the framework.
Let's first define the data structure of a plug-in, which certainly needs to be regulated by interfaces, which can be played freely according to your project. For example, I want the plug-in to have a Setup method to load at startup. Then I define the following Plugin structure.
Type Plugin interface {Name () string Setup (config map [string] string) error}
When the framework starts, I start a global variable like this:
Var plugins map [string] Plugin registration
One might ask, there is the loader function setup, but why is there no registration logic?
The answer is that the registered logic is placed in the library's init function.
That is, the framework also provides a registration function.
/ / package pluginRegister (plugin Plugin)
This register implements putting a third-party plugin into the plugins global variable.
So the third-party plugin library is roughly implemented as follows:
Package MyPlugintype MyPlugin struct {} func (m * MyPlugin) Setup (config map [string] string) error {/ / TODOfunc (m * MyPlugin) Name () string {return "myPlugin" func init () {plugin.Register (& MyPlugin)
So the logic of registration becomes that if you want to load a plug-in, you can simply introduce it in main.go in the form of _ import.
Package main_ import "github.com/foo/myplugin" func main () {}
On the whole, the registration of the plug-in is "hidden" into the import.
Load
The logic of registration actually seems mediocre, but the logic of loading tests the details.
First of all, there are two things to consider when loading a plug-in:
Configuration
Dependence
Configuration means that the plug-in must have some configuration that exists as the path to plugins.myplugin in the configuration file yaml.
Plugins: myplugin: foo: bar
In fact, I have reservations about this realization. Configuration files exist in the form of configuration items in a file, which seems to be better than configuration files, that is, files in config/plugins/myplugin.yaml.
This does not have the problem of a large configuration file. After all, each configuration file is itself an DSL language. If you complicate the logic of the configuration file, there must be a lot of accompanying bug caused by configuration file errors.
The second one is about dependence. Plug-in A depends on plug-in B, so there is the order in which the functions Setup are loaded. If this order depends solely on the user's "experience", it is very painful to put the Setup call of a plug-in before the Setup call of a plug-in. Although there must be a way to do it. A better approach is to rely on the loading mechanism of the framework itself to load.
First, we define an interface in the plugin package:
Type Depend interface {DependOn () [] string}
If my plug-in relies on a plug-in named "fooPlugin", then my plug-in MyPlugin will implement this interface.
Package MyPlugintype MyPlugin struct {} func (m * MyPlugin) Setup (config map [string] string) error {/ / TODOfunc (m * MyPlugin) Name () string {return "myPlugin" func init () {plugin.Register (& MyPlugin) func (m * MyPlugin) DependOn () [] string {return [] string {"fooPlugin"}
When we finally load all the plug-ins, we do not simply call all the plug-ins Setup, but use a channel, put all the plug-ins in channel, and then call Setup one by one. When we encounter other plug-ins in Depend and the dependent plug-ins have not been loaded, we put the current plug-in at the end of the queue (re-insert channel).
Var setupStatus map [string] bool// get all registered plug-ins func loadPlugins () (plugin chan Plugin, setupStatus map [string] bool) {/ / A queue of length 10 is defined here var sortPlugin = make (chan Plugin, 10) var setupStatus = make [string] bool// all plug-ins for name, plugin: = range plugins {sortPlugin 0 {plugin
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.