对于 Spring (boot),无需多言。PF4J 是一套开源的 Java 插件框架,全称为 Plugin Framework for Java ,可为 Java 应用提供模块化扩展的能力。
将 Spring 和 PF4J 结合起来,可为极大提高应用的灵活性以及可扩展能力,实现搭积木式的开发体验。核心思想非常简单,我们只要求 Spring 提供相关功能动态设置的 API 即可,幸运的是 Spring 提供了。这种热插拔的模式可能大部分实际系统可能用不上,更适用于通用性平台的开发。
首先大概梳理一下这个框架需要做哪些最基础的工作:
- 模块插件的 生命周期 管理,这方面主要有 PF4J 来负责。模块采用 jar 文件方式管理,可以通过上传模块的 jar 文件实现模块的动态添加
- 模块接口规范,可以根据实际需求进行定义。比如 HTTP 接口定义、返回值结果格式等,当然还有用于模块插件本身管理的一些接口
- 通过 Spring 相关 API,实现动态的组件注册。在适当的时机做适当的注册及销毁
- HTTP 接口参数及响应结果处理
下面一幅图应该可以勾画出整个思路的样貌。
模块插件的生命周期既然已经交由 PF4J 全权负责,就不需要过多的考虑,用好 PF4J 的接口就可以了。PF4J 的接口,我们主要用到的有加载、卸载以及插件信息这些。
之所以要定义接口规范,因为 PF4J 的插件是非常简单的,不足以支撑与 Spring 交互来达到目的。这里的接口规范,需要定义服务 API 入口、参数及响应结果。如:
// 模块插件定义接口
public interface ModulePlugin {
String getName();
int getVersion();
ModuleApiInfo[] getApiInfos();
}
// 模块 API 信息接口
public interface ModuleApiInfo {
String getPath();
Class<ModuleApi> getApiClass();
Class<Api Request > getRequestClass();
Class<ApiResponse> getResponseClass();
}
// 模块 API 接口
public interface ModuleApi {
ApiResponse service(ApiRequest request) throws Module Exception ;
}
// 请求参数接口
public interface ApiRequest {}
// 请求响应接口
public interface ApiResponse {}
前面示例了一个简单接口规范,提供了必要的因素,根据这些信息,就可以和 Spring 进行交互了。Spring 提供了 RequestMappingHandlerMapping 给开发者来实现动态注册 API的能力,有了它就可以注册和注销插件的 API 接口。结合起来,大概的过程就比较清晰了,请看下面的过程:
过程还是比较简单的,没有太复杂的逻辑。ApiRequest 和 ApiResponse 可以是空接口,通过 getRequestClass 和 getResponseClass 获取到 Class,利用 Java 的反射机制,框架核心逻辑就可以使用这两个 Class 对 API 参数和响应结果进行统一处理。
ApiRequest 的解释,可以通过两种途径,一种是定义 HttpMessageConverter ,另一种是自定义参数注解并实现 HandlerMethodArgumentResolver 。只要知道了实际的 Class,无论采用哪种方式都没有问题。
在一般的场景中,参数和响应结果可能需要统一封装一下,比如全局的服务结果码及响应消息等。
可以看到,核心的思路是相当简单的。我基于这个思路,曾经设计并实现了一套动态接口管理平台,要考虑的细枝末页还有很多,比如模块插件权限分配及控制、插件之间的依赖关系处理、插件版本的管理、插件注销等。更甚者也可以考虑实现 Service 及其它的 Spring组件动态加载,不过我觉得必要性不大,主要是插件的开发及调试就会变得更麻烦。