之前的文章《基于SPI的Java插件技术》有说这里的缺点:
“虽然ServiceLoader也算是使用的延迟加载,但是基本只能通过遍历全部获取,也就是接口的实现类全部加载并实例化一遍。如果你并不想用某些实现类,它也被加载并实例化了,这就造成了浪费。获取某个实现类的方式不够灵活,只能通过Iterator形式获取,不能根据某个参数来获取对应的实现类。”
今天吃饭的时候突然想到,我单独指定个地址不就好了,说干就干,也不是很复杂,写个json文件,用来指定插件名、插件地址:
{
"Plugin1": {
"address": "plugins/Plugin1.jar"
},
"Plugin2": {
"address": "plugins/Plugin2.jar"
}
}
其实这里也可以存数据库、用properties写配置、用yaml写配置都行,爱怎么弄怎么弄,我这里做个测试,就写json了。写个根据文件名加载指定插件的方法:
public IPluginService loadPlugin(String pluginName) throws Exception {
IPluginService pluginService = null;
// 获取 JSON 文件的输入流
InputStream inputStream = JSONReader.class.getResourceAsStream("/plugin.json");
String jsonText = null;
jsonText = IOUtils.toString(inputStream, "UTF-8");
// 使用 FastJSON 解析 JSON 字符串
JSONObject jsonObject = JSON.parseObject(jsonText);
// 可以使用 jsonObject 获取数据
JSONObject jsonPlugin = jsonObject.getJSONObject("Plugin1");
String address=jsonPlugin.getString("address");
// 关闭输入流
inputStream.close();
URL[] urls = new URL[]{new URL("file:" +address)};
URLClassLoader urlClassLoader = new URLClassLoader(urls);
ServiceLoader<IPluginService> serviceLoader = ServiceLoader.load(IPluginService.class, urlClassLoader);
return serviceLoader.iterator().next();
}
注释已经写得很清晰了,文章也就不用记了,当然我们用来测试的主程序也需要改一下:
public static void main(String[] args) throws MalformedURLException {
System.out.println("开始加载插件");
PluginLoader pluginLoader = new PluginLoader();
IPluginService service = null;
try {
service = pluginLoader.loadPlugin("Plugin1");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("插件加载成功n");
System.out.println("===插件===");
System.out.println("插件名:" + service.name());
System.out.println("版本号:" + service.version());
System.out.println("插件服务启动:");
service.service();
}
运行一下看下效果:
emmm,没啥毛病,程序已经放到github上,不得不说的是,今天一遍过,没有需要debug
原文始发于微信公众号(天幕安全团队):基于SPI的Java插件技术-加载指定插件
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论