插件通常以动态库的形式部署。动态库允许插件的很多优势如热交换(重新加载一个插件的新实现而无需关闭系统),而且需要更少的链接时间。然而,在某些情况下静态库是插件的最好选择。例如,仅仅因为某些系统不支持动态库(很多嵌入式系统)。在其他的情况下,出于安全考虑,不允许加载陌生的代码。有时,核心系统会与一些预先加载好插件一起部署,而且静态加载到主系统中使得它们更健壮(因此用户不会无意中删除它们)。
底线是,好的插件系统应当同时支持静态和动态插件。这可以让你在不同的环境下,不同的约束下部署同一个基于插件的系统。
插件编程接口
所以关于插件的问题都是关于接口(译注:要注意这里说的接口,不是C#和JAVA的接口概念,理解为signature更合适)的。基于插件的系统的基本观念是:有某个中央系统,通过定义良好的接口和协议,其在加载插件时不知道任何关于与插件通信的问题。
定义一系列函数作为插件导出的接口(动态库及静态库)是幼稚的方法。这种方法在技术上是可行的,但在概念上是有瑕疵的(译注:作者说话分量还是轻些)。原因是,插件应当支持两种接口且只能有一套从插件导出的函数。这表明这两种接口会被混合在一起。
第一层接口(及协议)是通用的插件接口。它使得中央系统可以初始化插件,并使插件可以在中央系统中注册一系列的用于创建和销毁对象以及全局的清理函数。通用插件接口不是与领域相关的,且可以被指定和实现为可服用的库。第二层接口是由插件对象实现的功能性的接口。该接口是领域相关的,且世纪的插件必须非常谨慎的对其进行设计和实现。中央系统应当知道该接口并能通过其与插件对象进行交互。
列表1是一个指定了通用插件接口的头文件。没有深入细节并解释所有事情之前,让我们看看它提供了什么。
#ifndef PF_PLUGIN_H
#define PF_PLUGIN_H
#include
#ifdef __cplusplus
extern "C" {
#endif
typedef enum PF_ProgrammingLanguage
{
PF_ProgrammingLanguage_C,
PF_ProgrammingLanguage_CPP
} PF_ProgrammingLanguage;
struct PF_PlatformServices_;
typedef struct PF_ObjectParams
{
const apr_byte_t * objectType;
const struct PF_PlatformServices_ *
platformServices;
} PF_ObjectParams;
typedef struct PF_PluginAPI_Version
{
apr_int32_t major;
apr_int32_t minor;
} PF_PluginAPI_Version;
typedef void * (*PF_CreateFunc)(PF_ObjectParams *);
typedef apr_int32_t (*PF_DestroyFunc)(void *);
typedef struct PF_RegisterParams
{
PF_PluginAPI_Version version;
PF_CreateFunc createFunc;
PF_DestroyFunc destroyFunc;
PF_ProgrammingLanguage
programmingLanguage;
} PF_RegisterParams;
typedef apr_int32_t (*PF_RegisterFunc)(const apr_byte_t *
nodeType, const PF_RegisterParams * params);
typedef apr_int32_t (*PF_InvokeServiceFunc)(const apr_byte_t *
serviceName, void * serviceParams);
typedef struct PF_PlatformServices
{
PF_PluginAPI_Version version;
PF_RegisterFunc registerObject;
PF_InvokeServiceFunc invokeService;
} PF_PlatformServices;
typedef apr_int32_t (*PF_ExitFunc)();
typedef PF_ExitFunc (*PF_InitFunc)(const PF_PlatformServices
*);
#ifndef PLUGIN_API
#ifdef WIN32
#define
PLUGIN_API __declspec(dllimport)
#else
#define
PLUGIN_API
#endif
#endif
extern
#ifdef __cplusplus
"C"
#endif
PLUGIN_API PF_ExitFunc PF_initPlugin(const PF_PlatformServices *
params);
#ifdef __cplusplus
}
#endif
#endif
列表1
首先你应当注意到这是一个C文件。这允许插件框架可以由纯C系统编译使用并可用来写纯C插件。但是,它不仅仅局限在C上,且实际上大多数情况下用在C++中。
枚举类型PF_ProgrammingLanguage允许插件声明到用C++实现的插件管理器中。
PF_ObjectParams是一个抽象的结构体,创建插件时用于传递参数