我决定在我的glassfish Web应用程序中实现动态类加载,作为尝试它的一种方式,并支持可在运行时由Web应用程序加载和执行的小插件。
我添加了以下课程:
public class PluginManager {
private static final String dropBoxDir = "file:///path/to/dropbox/";
private static final URLClassLoader dropBoxClassLoader;
static {
try {
URL dropBoxURL = new URL(dropBoxDir);
dropBoxClassLoader = URLClassLoader.newInstance(new URL[]{dropBoxURL});
}
catch (MalformedURLException mue) {
throw new RuntimeException("MalformedURLException thrown during PluginManager initialization - the hardcoded URL " + dropBoxDir + " must be invalid.", mue);
}
}
//this method is called by a web service
public static void runPluginFromDropBox(String fullClassName) {
try {
//load the plugin class
Class<?> pluginClass = dropBoxClassLoader.loadClass(fullClassName);
//instantiate it
Runnable plugin = (Runnable)pluginClass.newInstance();
//call its run() method
plugin.run();
}
catch (ClassNotFoundException cnfe) {
throw new RuntimeException("The class file for " + fullClassName + " could not be located at the designated directory (" + dropBoxDir + "). Check that the specified class name is correct, and that its file is in the right location.", cnfe);
}
catch (InstantiationException ie) {
throw new RuntimeException("InstantiationException thrown when attempting to instantiate the plugin class " + fullClassName + " - make sure it is an instantiable class with a no-arg constructor.", ie);
}
catch (IllegalAccessException iae) {
throw new RuntimeException("IllegalAccessException thrown when attempting to instantiate the plugin class " + fullClassName + " - make sure the class and its no-arg constructor have public access.", iae);
}
catch (ClassCastException cce) {
throw new RuntimeException("Plugin instance could not be cast to Runnable - plugin classes must implement this interface.", cce);
}
}
}
然后在一个单独的项目中,我创建了一个测试插件:
public class TestPlugin implements Runnable {
@Override
public void run() {
System.out.println("plugin code executed");
}
}
我部署了Web应用程序,然后将TestPlugin
编译成.class
文件并将其放入指定的文件夹中。我调用了一个Web服务,它使用类名命中runPluginFromDropBox()
并得到了预期的输出。
这一切都可以作为概念证明,但我的插件实际上是无用的,除非它可以让我知道我的Web应用程序的类。我已经读过.war
仅作为一个独立的应用程序,并不打算在其他库的类路径上,这对这个小方案项目来说不是好兆头。
我看了一下这个讨论:Extending Java Web Applications with plugins并且感觉我正在淹没设计挑战的沼泽,没有太大的理由,应该转过身来。然而,这篇文章有点陈旧,并且是特定于Tomcat的,所以我想我会问,如果没有一些精心设计的第三方框架,我是否有任何直接的方式来解决这个问题。
答案 0 :(得分:2)
war文件的类由特定的类加载器加载,以将战争与部署在同一服务器上的其他webapp隔离,并且能够取消部署战争。
要了解webapp类,您的插件类加载器应该将webapp类加载器作为其父类。我不知道使用额外的类加载器可能会遇到的所有问题,但我怀疑当容器取消部署并重新部署webapp时,你可能会遇到内存泄漏和其他令人讨厌的问题(静态值保留在内存中等)。而且容器之间也可能存在差异。