我正在编写一个 Spring Boot API 应用程序,它必须具有插件架构。下面是一个典型的旅程:
- 我的应用程序可以执行任务(接受一些输入并返回输出)
- 我有一个
TaskExecutor
用一些方法调用的接口(例如execute(Object... inputArgs)
:) - 我的应用程序的用户编写了一个插件来处理特定任务(用户只需实现该
TaskExecutor.execute(Object... args)
方法以满足任务的要求)。该插件被打包为.jar
- 我的应用程序中有一个名为Install new Plugin的屏幕,用户可以在其中上传
.jar
包含插件的文件。例如,用户上传了一个名为的新插件并定义了一个名为Send Emailsend-email-plugin-1.0.jar
的新任务类型。 - 上传后,系统会将 jar 加载到其类路径中。
- 每当用户创建一个类型为Send Email的新任务并运行它时,就会调用
TaskExecutor
in 的实现。send-email-plugin-1.0.jar
我想满足以下要求:
- 插件应该在运行时加载
- 它应该
.jar
按需卸载/更新(当有新文件时) - 我必须能够对其进行沙箱处理并允许/限制对主机上某些资源的访问。
- 宿主应用程序不需要
beans
从插件访问任何内容 - 我们可以将插件视为无弹簧部件(因为没有更好的术语)
我浏览过有关OSGi、PF4j和其他的文章,但似乎无法完全理解它们——它们对于我的用例来说看起来很复杂(我不确定)
到目前为止我已经尝试过:
作为一段非常基本的代码,我尝试做这样的事情(假设我将用户上传的 jar 文件存储在文件系统的某个位置)。
@SuppressWarnings({ "rawtypes", "resource" })
// pluginName: name of the plugin (or the JAR file)
// entryPointClass: full name of the implementation class of TaskExecutor within this plugin. For ex: com.myorg.plugins.EmailTaskExecutorImpl
public synchronized TaskExecutor loadAdapter(String pluginName, String entryPointClass) {
try {
URL jarUrl = getJarAsURL(pluginName);
ClassLoader systemClassLoader = TaskExecutor.class.getClassLoader();
ClassLoader customLoader = new URLClassLoader(new URL[] {jarUrl}, systemClassLoader);
Class pluginEntryPoint = customLoader.loadClass(entryPointClass);
Object pluginEntryPointObject = pluginEntryPoint.newInstance();
return (TaskExecutor) pluginEntryPointObject;
} catch (MalformedURLException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
log.error("Error loading JAR for {}", pluginName, e);
return null;
}
}
它能够在运行时加载插件并执行作业。但是,显然它不会执行以下操作:
- 不处理更新(如果我想将插件升级到 2.0 版怎么办?)
- 它不是沙盒的。拥有对服务器的完全访问权限。我怎样才能防止这种情况?
- 我必须考虑的任何线程安全/漏洞?
请有人指出我正确的方向。
谢谢,斯里拉姆