插件熱插拔管理機制,簡稱:H-Spi。是框架提供的生產時用的另一種高級擴展方案。相對E-Spi,H-Spi 更側重隔離、熱插熱拔、及管理性。
應用時,是以一個業務模塊爲單位進行開發,且封裝爲一個獨立插件包。
1、特點說明
- 所有插件包獨享ClassLoader、AopContext、配置;完全隔離
- 可通過 Solon.app(), Solon.cfg(), Solon.context() 等...手動獲取主程序或全局的資源
- 模塊可以打包成一個獨立的插件包(放在體外加載),也可以與主程序一起打包。“分”或“合”也是自由!
- 更新插件包,不需要重啓主服務。熱更新!
- 開發時,所有資源完全獨立自控。且必須完成資源移除的任務
- 模塊之間的通訊,儘量交由事件總線(EventBus)處理。且儘量用弱類型的事件數據(如Map,或 JsonString)
- 主程序需要引入 "solon.hotplug" 依賴,對業務插件包進行管理
2、插件開發注意示例
- 插件在“啓動”時添加到公共場所的資源或對象,必須在插件停止時須移除掉(爲了能熱更新):
public class Plugin1Impl implements Plugin {
AopContext context;
StaticRepository staticRepository;
@Override
public void start(AopContext context) {
this.context = context;
//添加自己的配置文件
this.context.cfg().loadAdd("demo1011.plugin1.yml");
//掃描自己的bean
this.context.beanScan(Plugin1Impl.class);
//添加自己的靜態文件倉庫(註冊classloader)
staticRepository = new ClassPathStaticRepository(context.getClassLoader(), "plugin1_static");
StaticMappings.add("/html/", staticRepository);
}
@Override
public void stop() throws Throwable {
//移除http處理。//用前綴,方便移除
Solon.app().router().remove("/user");
//移除定時任務(如果有定時任務,選支持手動移除的方案)
JobManager.remove("job1");
//移除事件訂閱
context.beanForeach(bw -> {
if (bw.raw() instanceof EventListener) {
EventBus.unsubscribe(bw.raw());
}
});
//移除靜態文件倉庫
StaticMappings.remove(staticRepository);
}
}
- 一些涉及 classloader 的相關細節,需要多多注意。比如後端模板的渲染:
public class BaseController implements Render {
//要考慮模板所在的classloader
static final FreemarkerRender viewRender = new FreemarkerRender(BaseController.class.getClassLoader());
@Override
public void render(Object data, Context ctx) throws Throwable {
if (data instanceof Throwable) {
throw (Throwable) data;
}
if (data instanceof ModelAndView) {
viewRender.render(data, ctx);
} else {
ctx.render(data);
}
}
}
- 更多細節,需要根據業務情況多多注意。
3、插件管理
插件有管理能力後,還可以倉庫化,平臺化。詳見:《生態 / Solon / solon.hotplug》