前言
本文是前一文章的继续,主要是开始着手Python脚本代码的实现。预期来说,本文将完成以下功能:
- 加载2个插件;
- 实现一个简化的插件上下文;
- 实现一个简化的插件加载框架;
- 实现一个主程序;
- 实现扩一个扩展演示;
- 实现一个服务注册演示;
- 实现一个订阅演示;
代码仓库:https://gitee.com/imlaji/PythonPluginFW
实现逻辑
预期两个插件中,一个负责APP启动,另一个负责扩展实现。APP扩展点名是一个系统默认扩展点,名称为PL::APP,扩展点接口定义为:
class APP:
def name(self):
return ""
def run(self, argv):
return ""
主程序
主程序负责驱动插件框架加载插件,然后在插件上下文中查询PL::APP扩展,使用指定名称的APP扩展进行应用启动执行。
import context
import framework
import sys
def main():
plcontext = context.context()
pl = framework.framework()
pl.load(plcontext, "./plugins")
apps = plcontext.find_extension("PL::APP")
app = None
for a in apps:
if a.name() == "MyApp":
app = a
break
if app == None:
print("PL::APP not match!")
else:
app.run(sys.argv)
main()
插件框架
插件框架负责动态加载目录中的插件,为了简单,本例暂时使用静态加载。后续版本进行修改完善。
import plugins.plugina.plugin as plugina
import plugins.pluginb.plugin as pluginb
class framework:
def load(self, context, path):
plugina.init(context)
pluginb.init(context)
for ex in plugina.config["extensions"]:
context.add_extension(ex['name'], ex['impl'])
for service in plugina.config["services"]:
context.add_service(service['name'], service['define'])
#for subscribe in plugina.config["subscribes"]:
# context.add_subscribe(subscribe['name'], subscribe['define'])
for ex in pluginb.config["extensions"]:
context.add_extension(ex['name'], ex['impl'])
#for service in pluginb.config["services"]:
# context.add_service(service['name'], service['define'])
for subscribe in pluginb.config["subscribes"]:
context.add_subscribe(subscribe['name'], subscribe['define'])
print("Hello!")
插件上下文
插件上下文主要记录了插件框架的所有数据信息,是插件框架的核心数据中心。
class context:
plugins = []
extensions = {}
services = {}
subscribes = {}
def add_plugin(self, plugin):
self.plugins.append(plugin)
def get_plugins(self):
return self.plugins
def add_extension(self, extype, ext):
if not extype in self.extensions:
self.extensions[extype] = []
self.extensions[extype].append(ext)
def find_extension(self, extype):
if extype in self.extensions:
return self.extensions[extype]
else:
return []
def add_service(self, name, service):
self.services[name] = service
def find_service(self, name):
if name in self.services:
return self.services[name]
else:
return None
def add_subscribe(self, name, callback):
if not name in self.subscribes:
self.subscribes[name] = []
self.subscribes[name].append(callback)
def fire(self, name, value):
if name in self.subscribes:
for callback in self.subscribes[name]:
callback(value)
APP插件
APP插件实现了框架默认的PL::APP扩展点。并且定义了新的扩展点,也定义了一个服务,同时出发了一个订阅事件。
context = None
def init(context_):
global context
context = context_
class MyApp:
def name(self):
return "MyApp"
def run(self, argv):
context.fire("Event1", {"id", 20})
exts = context.find_extension("PL::Test1")
for ext in exts:
ext.test()
print("Hello in MyAPP!!")
class MyTest:
def test(self):
print("Hello Test!")
def HelloServiceFun(a, b):
print("HelloService:", a+b)
config = {
"extensions" : [
{
"name": "PL::APP",
"impl": MyApp()
}
],
"extensions_def" : [
{
"name": "PL::Test1",
"define": MyTest
}
],
"services" : [
{
"name": "HelloService",
"define": HelloServiceFun
}
]
}
插件b
插件b完全就是为了配合APP插件,完成相关功能的交互。实现了APP插件扩展的插桩点,并且使用了APP插件的服务,同时订阅了一个事件消息。
context = None
def init(context_):
global context
context = context_
class MyApp:
def name(self):
return "MyApp"
def run(self, argv):
print("Hello in MyAPP!!")
class MyTest:
def test(self):
print("Hello Test222!")
def MyEventFun(val):
service = context.find_service("HelloService")
if (service):
service(30, 40)
print("MyEventFun:", val)
config = {
"extensions" : [
{
"name": "PL::Test1",
"impl": MyTest()
}
],
"subscribes" : [
{
"name": "Event1",
"define": MyEventFun
}
]
}
总结
当我们理清我们想要什么,就会发现实现一个插件框架是非常快的。本文主要演示了插件框架的基本概念实现,后续文章将继续针对本插件框架进行结构优化,动态加载插件,定义框架本身事件,服务添加属性描述等,并逐步开始添加UI的交互。
网友评论