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

标签 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 特定的,所以我只是想问是否有任何简单的方法可以让我在没有一些复杂的第三方框架的情况下解决这个问题。

最佳答案

war 文件的类由特定的类加载器加载,以将 war 与部署在同一服务器上的其他 Web 应用程序隔离,并能够取消部署 war。

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

关于java - 如何使动态加载的插件能够感知 Web 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7219429/

相关文章:

plugins - 在点击和加载事件时播放暂停背景音频

java - 我们需要解决ConcurrentModificationException吗?

java - 没有@Id的 hibernate/持久性

objective-c - 是否可以为 OSX Preview 编写插件?

javascript - 在 jQuery 日期选择器插件中仅显示周末

java - 如何获取 REST 请求的 HTTP 方法

Javax Websocket 由于非法 UTF-8 序列而关闭

java - 无法为JAX-B生成架构,仅在CORS调用REST服务期间发生

java - 如何打开AppCompatActivity类?

java - openCV java绑定(bind)不生成VideoWriter类