我使用Netbeans创建了一个javafx项目,项目本身运行得很好。
我现在正在尝试实现自定义轻量级插件系统,插件是位于主项目的plugins/
目录内的外部JAR。我正在使用javax.security
包来插入插件。
这是主要项目的结构:
MainProject
|
|---plugins/
| |---MyPlugin.jar
|
|---src/
| |---main.app.plugin
| |---Plugin.java
| |---PluginSecurityPolicy.java
| |---PluginClassLoader.java
| |---PluginContainer.java
....
插件的一个:
Plugin
|
|---src/
| |---my.plugin
| | |---MyPlugin.java
| |--settings.xml
|
|---dist/
|---MyPlugin.jar
|---META-INF/
| |---MANIFEST.MF
|---my.plugin
| |---MyPlugin.class
|---settings.xml
要将插件加载到程序中,我创建了一个PluginContainer
类,它从plugins目录中获取所有jar文件,列出jar中的所有文件,并查找插件文件和设置文件。 / p>
我可以加载并创建插件类的实例,但是当涉及到XML时,我甚至无法在jar内容中列出它。
这是代码,也许有人可以看到我做错了。
PluginSecurityPolicy.java
import java.security.AllPermission;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.Policy;
import java.security.ProtectionDomain;
public class PluginSecurityPolicy extends Policy {
@Override
public PermissionCollection getPermissions(ProtectionDomain domain) {
if (isPlugin(domain)) {
return pluginPermissions();
} else {
return applicationPermissions();
}
}
private boolean isPlugin(ProtectionDomain domain) {
return domain.getClassLoader() instanceof PluginClassLoader;
}
private PermissionCollection pluginPermissions() {
Permissions permissions = new Permissions();
//
return permissions;
}
private PermissionCollection applicationPermissions() {
Permissions permissions = new Permissions();
permissions.add(new AllPermission());
return permissions;
}
}
PluginClassLoader.java
import java.net.URL;
import java.net.URLClassLoader;
public class PluginClassLoader extends URLClassLoader {
public PluginClassLoader(URL jarFileUrl) {
super(new URL[] {jarFileUrl});
}
}
PluginContainer.java,#load
方法就是那个
import main.app.plugin.PluginClassLoader;
import main.app.plugin.PluginSecurityPolicy;
import java.io.File;
import java.net.URL;
import java.security.Policy;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class PluginContainer {
private ArrayList<Plugin> plugins;
private ManifestParser parser;
public PluginContainer() {
Policy.setPolicy(new PluginSecurityPolicy());
System.setSecurityManager(new SecurityManager());
plugins = new ArrayList<>();
parser = new ManifestParser();
}
public void init() {
File[] dir = new File(System.getProperty("user.dir") + "/plugins").listFiles();
for (File pluginJarFile : dir) {
try {
Plugin plugin = load(pluginJarFile.getCanonicalPath());
plugins.add(plugin);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
public <T extends Plugin> T getPlugin(Class<T> plugin) {
for (Plugin p : plugins) {
if (p.getClass().equals(plugin)) {
return (T)p;
}
}
return null;
}
private Plugin load(String pluginJarFile) throws Exception {
PluginManifest manifest = null;
Plugin plugin = null;
// Load the jar file
ZipFile jarFile = new ZipFile(pluginJarFile);
// Get all jar entries
Enumeration allEntries = jarFile.entries();
String pluginClassName = null;
while (allEntries.hasMoreElements()) {
// Get single file
ZipEntry entry = (ZipEntry) allEntries.nextElement();
String file = entry.getName();
// Look for classfiles
if (file.endsWith(".class")) {
// Set class name
String classname = file.replace('/', '.').substring(0, file.length() - 6);
// Look for plugin class
if (classname.endsWith("Plugin")) {
// Set the class name and exit loop
pluginClassName = classname;
break;
}
}
}
// Load the class
ClassLoader pluginLoader = new PluginClassLoader(new URL("file:///" + pluginJarFile));
Class<?> pluginClass = pluginLoader.loadClass(pluginClassName);
// Edit as suggested by KDM, still null
URL settingsUrl = pluginClass.getResource("/settings.xml");
manifest = parser.load(settingsUrl);
// Check if manifest has been created
if (null == manifest) {
throw new RuntimeException("Manifest file not found in " + pluginJarFile);
}
// Create the plugin
plugin = (Plugin) pluginClass.newInstance();
plugin.load(manifest);
return plugin;
}
}
自动生成的MANIFEST.MF
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.9.4
Created-By: 1.8.0_25-b18 (Oracle Corporation)
Class-Path
指令丢失了,但是如果我强制它.
或./settings.xml
或settings.xml
(通过手动编辑MANIFEST.MF
文件),它就赢了不管怎样。
这是我所能想到的,预先感谢您的帮助
[编辑]我在插件jar根中创建了images/monitor-16.png
,将#load2
方法添加到PluginContainer
。
由于在循环中调用该方法,我将Policy.setPolicy(new PluginSecurityPolicy());
和System.setSecurityManager(new SecurityManager());
留在构造函数中。
这是新的plugn jar结构:
TestPlugin.jar
|
|---META-INF/
| |---MANIFEST.MF
|
|---dev.jimbo
| |---TestPlugin.class
|
|---images
| |---monitor-16.png
|
|---settings.xml
新方法代码:
private Plugin load2(String pluginJarFile) throws MalformedURLException, ClassNotFoundException {
PluginClassLoader urlCL = new PluginClassLoader(new File(pluginJarFile).toURL());
Class<?> loadClass = urlCL.loadClass("dev.jimbo.TestPlugin");
System.out.println(loadClass);
System.out.println("Loading the class using the class loader object. Resource = " + urlCL.getResource("images/monitor-16.png"));
System.out.println("Loading the class using the class loader object with absolute path. Resource = " + urlCL.getResource("/images/monitor-16.png"));
System.out.println("Loading the class using the class object. Resource = " + loadClass.getResource("images/monitor-16.png"));
System.out.println();
return null;
}
这是输出
class dev.jimbo.TestPlugin
Loading the class using the class loader object. Resource = null
Loading the class using the class loader object with absolute path. Resource = null
Loading the class using the class object. Resource = null
答案 0 :(得分:0)
以下计划:
public static void main(String[] args) throws MalformedURLException, ClassNotFoundException {
Policy.setPolicy(new PluginSecurityPolicy());
System.setSecurityManager(new SecurityManager());
PluginClassLoader urlCL = new PluginClassLoader(new File(
"A Jar containing images/load.gif and SampleApp class").toURL());
Class<?> loadClass = urlCL.loadClass("net.sourceforge.marathon.examples.SampleApp");
System.out.println(loadClass);
System.out.println("Loading the class using the class loader object. Resource = " + urlCL.getResource("images/load.gif"));
System.out.println("Loading the class using the class loader object with absolute path. Resource = " + urlCL.getResource("/images/load.gif"));
System.out.println("Loading the class using the class object. Resource = " + loadClass.getResource("images/load.gif"));
}
产生以下输出:
class net.sourceforge.marathon.examples.SampleApp
Loading the class using the class loader object. Resource = jar:file:/Users/dakshinamurthykarra/Projects/install/marathon/sampleapp.jar!/images/load.gif
Loading the class using the class loader object with absolute path. Resource = null
Loading the class using the class object. Resource = null
所以我认为您的类加载器没有任何问题。将此作为答案,以便可以正确格式化代码。
答案 1 :(得分:0)
钉了它!似乎我之前的Netbeans(8.0)正在从清理和构建操作中添加的Jar / Folder Libraries引用中删除plugin
目录。我已经下载并安装了Netbeans 8.0.2,问题解决了。但是在他们的跟踪器上找不到该版本的任何相关错误..
无论如何感谢您的帮助:)