[英]How to load resources.properties from local directory, not the JAR in Java?
[英]Java load jar files from directory
我目前正在开发一个开源项目,人们可以在其中添加自己的.jar来扩展所包含的功能。 但是,我对如何在jar中加载类感到困惑。
我有一个抽象类,它具有一个抽象方法onEnable()
和一些getter,该方法提供了一些可与应用程序一起使用的对象。 插件需要我的插件类BasePlugin
的子类。 该jar应该添加到/ plugins中,因此我希望在应用程序启动时加载/ plugins文件夹中的所有* .jar文件。
我现在遇到的问题是,在找到的所有方法中,我需要在jar文件中声明类的类路径,这是我所不知道的。 我也不知道jar文件的名称。 因此,我需要扫描/ plugins文件夹中的任何* .jar文件,并将相应的类加载到实现BasePlugin
的jar中,并调用onEnable()
方法。
基本想法也是...
File
引用转换为每个结果的URL
URLClassLoader
(以URL
结果作为种子)来加载每个结果 URLClassLoader#findResources
查找具有特定名称的所有匹配资源 例如...
public List<PluginClass> loadPlugins() throws MalformedURLException, IOException, ClassNotFoundException {
File plugins[] = new File("./Plugins").listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return file.getName().endsWith(".jar");
}
});
List<URL> plugInURLs = new ArrayList<>(plugins.length);
for (File plugin : plugins) {
plugInURLs.add(plugin.toURI().toURL());
}
URLClassLoader loader = new URLClassLoader(plugInURLs.toArray(new URL[0]));
Enumeration<URL> resources = loader.findResources("/META-INFO/Plugin.properties");
List<PluginClass> classes = new ArrayList<>(plugInURLs.size());
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
Properties properties = new Properties();
try (InputStream is = resource.openStream()) {
properties.load(is);
String className = properties.getProperty("enrty-point");
PluginClass pluginClass = loader.loadClass(className);
classes.add(pluginClass);
}
}
return classes
}
nb:我还没有运行,但这是“基本
Java已经为此提供了一个类: ServiceLoader 。
Java 6引入了ServiceLoader类,但是“ SPI jar”概念实际上与Java 1.3一样古老。 想法是,每个jar包含一个简短的文本文件,该文件描述了特定服务提供者接口的实现。
例如,如果一个.jar文件包含两个名为FooPlugin和BarPlugin的BasePlugin子类,则.jar文件还将包含以下条目:
META-INF/services/com.example.BasePlugin
该jar条目将是一个文本文件,其中包含以下几行:
com.myplugins.FooPlugin
com.myplugins.BarPlugin
您的项目将通过创建从plugins
目录读取的ClassLoader来扫描plugins
:
Collection<URL> urlList = new ArrayList<>();
Path pluginsDir = Paths.get(
System.getProperty("user.home"), "plugins");
try (DirectoryStream<Path> jars =
Files.newDirectoryStream(pluginsDir, "*.jar")) {
for (Path jar : jars) {
urlList.add(jar.toUri().toURL());
}
}
URL[] urls = urlList.toArray(new URL[0]);
ClassLoader pluginClassLoader = new URLClassLoader(urls,
BasePlugin.class.getClassLoader());
ServiceLoader<BasePlugin> plugins =
ServiceLoader.load(BasePlugin.class, pluginClassLoader);
for (BasePlugin plugin : plugins) {
plugin.onEnable();
// etc.
}
使用ServiceLoader的另一个优点是您的代码将能够使用模块,这是Java 9引入的一种更完整的代码封装形式,可提高安全性。
有一个例子在这里可能会有所帮助。 另外,您应该看看OSGi。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.