插件定义与开发
这篇文档说明当前 Geelato 插件应该如何定义扩展点、实现插件、打包插件,以及与宿主工程之间的依赖边界。
本文结合:
服务端插件开发指引.mdgeelato-plugin-allgeelato-example-plugin
进行整理。
开发时的模块分层
当前推荐把插件开发拆成两部分:
- 扩展点契约层
- 插件实现层
扩展点契约层
放在:
geelato-plugin-all
这里主要定义:
PluginExtensionPoint- 具体业务扩展接口
- 共享的
PluginInfo - 共享 DTO / VO / 元数据对象
例如:
cn.geelato.plugin.example.Greeting
插件实现层
放在具体插件模块里,例如:
geelato-example-plugingeelato-ocr-plugin
这里主要包含:
- 插件主类
- 插件 Spring 配置
- 扩展实现类
plugin.properties
第 1 步:定义扩展点接口
当前基础扩展点接口是:
PluginExtensionPoint
它本身继承:
ExtensionPoint
业务接口要继续继承它,例如:
public interface Greeting extends PluginExtensionPoint {
String getGreeting();
}
这样宿主工程和插件实现就会围绕同一个扩展接口协作。
第 2 步:实现插件主类
当前示例插件主类是:
HelloPlugin
它继承:
SpringPlugin
并重写:
createApplicationContext()
典型写法是:
- 创建
AnnotationConfigApplicationContext - 设置插件自己的
ClassLoader - 注册插件自己的 Spring 配置类
refresh()
这表示当前插件不是简单静态类集合,而是可以拥有:
- 自己的 Spring 容器
- 自己的 Bean 定义
- 自己的内部依赖关系
第 3 步:定义插件内部 Spring 配置
示例里使用:
ExamplePluginConfiguration
这个类负责在插件上下文里声明自己的 Bean,例如:
GreetingService
这样插件扩展实现类就可以直接使用:
@Autowired
注入插件内部服务。
第 4 步:实现扩展类
示例扩展类是:
HelloGreeting
关键点有两个:
- 实现扩展点接口
Greeting - 添加
@Extension
例如:
@Extension
public class HelloGreeting implements Greeting {
@Autowired
private GreetingService greetingService;
@Override
public String getGreeting() {
return greetingService.rtnString();
}
}
这里说明当前实现支持:
- PF4J 扩展点发现
- 插件内部 Spring Bean 注入
第 5 步:配置 plugin.properties
示例插件中:
src/main/plugin.properties
当前包含:
plugin.classplugin.dependenciesplugin.idplugin.providerplugin.version
示例:
plugin.class=cn.geelato.plugin.example.HelloPlugin
plugin.dependencies=x, y, z
plugin.id=example-plugin
plugin.provider=geelato
plugin.version=0.0.1
这些字段描述的是:
- 插件主类
- 插件 ID
- 插件版本
- 插件提供者
- 插件依赖关系
第 6 步:打包插件
当前插件模块需要在 pom.xml 中至少关注两件事:
依赖 plugin-all
例如示例插件依赖:
cn.geelato:plugin-all
这是为了拿到:
- 扩展点接口
- 共享契约对象
配置 PF4J 扩展注解处理器
示例里通过:
maven-compiler-plugin
声明:
org.pf4j.processor.ExtensionAnnotationProcessor
这是为了生成:
META-INF/extensions.idx
没有这个文件,扩展点发现通常会失败。
配置 JAR Manifest
示例插件还通过:
maven-jar-plugin
写入:
Plugin-ClassPlugin-IdPlugin-VersionPlugin-DescriptionPlugin-Provider
这部分是 PF4J 识别插件包的重要元数据。
打包后应检查什么
打包成功后,建议检查插件 jar 至少包含:
META-INF/extensions.idxMETA-INF/MANIFEST.MFplugin.properties
如果缺少这些内容,通常意味着:
- 扩展注解处理器未生效
- 插件主类元数据未写入
- 插件描述文件位置不正确
推荐目录结构
当前推荐结构仍然是:
example-plugin
├─ pom.xml
└─ src
└─ main
├─ java
│ └─ cn/geelato/plugin/example
│ ├─ HelloPlugin.java
│ ├─ ExamplePluginConfiguration.java
│ ├─ HelloGreeting.java
│ └─ GreetingService.java
└─ plugin.properties
而扩展点接口则放在:
geelato-plugin-all
宿主工程如何调用插件
宿主工程标准调用方式是:
- 注入
PluginBeanProvider - 通过接口类型和插件 ID 获取扩展实例
- 调用扩展方法
例如:
Greeting greeting = pluginBeanProvider.getBean(Greeting.class, "example-plugin");
String result = greeting.getGreeting();
如果拿不到扩展,当前会抛出:
UnFoundPluginException
所以调用侧要做好异常兜底。
当前开发建议
- 共享接口始终放在
geelato-plugin-all - 插件实现不要把宿主工程强耦合进去
- 插件主类优先继承
SpringPlugin - 每个扩展实现都明确加
@Extension - 尽量让插件内部 Bean 都收敛到插件自己的配置类中
- 对插件 ID、版本号、
plugin.properties和 JAR Manifest 保持一致