如何使动态加载的插件Web应用程序感知

时间:2011-08-28 06:41:19

标签: java plugins glassfish classloader war

我决定在我的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的,所以我想我会问,如果没有一些精心设计的第三方框架,我是否有任何直接的方式来解决这个问题。

1 个答案:

答案 0 :(得分:2)

war文件的类由特定的类加载器加载,以将战争与部署在同一服务器上的其他webapp隔离,并且能够取消部署战争。

要了解webapp类,您的插件类加载器应该将webapp类加载器作为其父类。我不知道使用额外的类加载器可能会遇到的所有问题,但我怀疑当容器取消部署并重新部署webapp时,你可能会遇到内存泄漏和其他令人讨厌的问题(静态值保留在内存中等)。而且容器之间也可能存在差异。