我正在为Web服务器应用程序开发一个插件系统,并且遇到了需要外部库(jar不是本机库)的插件的问题。由于我加载插件的方式(在应用程序启动后),我找不到动态加载这些jar库供插件使用的方法。
插件编译为jar,必须在jar中包含一个名为plugin.info的文件。此文件遵循以下格式:
main=x.y.z.PluginMainClass (the main class of the plugin to be loaded and instantiated by the application - as shown below)
load-lib=jsocket.jar
load-class=com.jsocket.Server
load-class=com.jsocket.Client
这是我加载插件的相关部分:
JarFile jarFile = new JarFile(file);
Enumeration<JarEntry> e = jarFile.entries();
URL[] urls = { new URL("jar:file:" + file.getPath() + "!/") };
URLClassLoader cl = URLClassLoader.newInstance(urls);
String pluginClass = "";
File loadLib = null;
URLClassLoader libLoader = null;
ArrayList<String> postLoad = new ArrayList<String>();
ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
while (e.hasMoreElements()) {
JarEntry je = (JarEntry) e.nextElement();
if(je.isDirectory() || !je.getName().endsWith(".class")){
if(je.getName().equals("plugin.info")){
String dat = readStringFromJarEntry(je);
for(String line : dat.split("\n")){
String[] parts = line.split(Pattern.quote("="));
if(parts.length < 2)continue;
if(parts[0].equals("main"))
pluginClass = parts[1];
else if(parts[0].equals("load-lib")){
File libFile = new File("./lib", parts[1]);
libLoader = URLClassLoader.newInstance(new URL[] { new URL("jar:file:" + libFile.getPath() + "!/") });
}else if(parts[0].equals("load-class")){
libLoader.loadClass(parts[1]);//Class<?> cls = Class.forName(parts[1], true, libLoader);//THIS WORKS FINE WITH NO EXCEPTIONS
}
}
}
continue;
}
String className = je.getName().substring(0, je.getName().length() - 6);
postLoad.add(className);
}
//Load all classes in plugin jar
for(String className : postLoad){
log.d("Loading plugin class " + className);
className = className.replace('/', '.');
Class<?> c = cl.loadClass(className);
classes.add(c);
}
jarFile.close();
for(Class<?> cls : classes){
if(cls.getCanonicalName().equals(pluginClass)){
Object plug = cls.newInstance();
if(plug instanceof IPlugin){
IPlugin iplug = (IPlugin)plug;
plugins.add(iplug);//plugins is an arraylist of objects implementing IPlugin
}
}
}
(对不起,但是有必要使用冗长的代码)
以下是该插件主要类的片段:
@Override
public void init(){
Server server = new Server(1221);//Reference to Server class in jsocker lib (first arg is port)
}
如您所见,该插件使用jsocket库中的类。我使用URLClassLoader#loadClass
从jsocket lib加载了类,但在初始化插件时出现以下错误:
Exception in thread "main" java.lang.NoClassDefFoundError: com/jsocket/Server
如何修复此问题并将URLClassLoader#loadClass
加载类转换为类路径?