开发者

how to make a dynamically loaded plugin web application-aware

开发者 https://www.devze.com 2023-03-31 19:38 出处:网络
I decided to implement dynamic class loading in my glassfish web application, as a way of trying it out and to support small plugins that could be loaded and executed by the web app at runtime.

I decided to implement dynamic class loading in my glassfish web application, as a way of trying it out and to support small plugins that could be loaded and executed by the web app at runtime.

I added the following class:

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开发者_StackOverflow社区 to Runnable - plugin classes must implement this interface.", cce);
      }
   }
}

Then in a separate project, I created a test plugin:

public class TestPlugin implements Runnable {
   @Override
   public void run() {
      System.out.println("plugin code executed");
   }
}

I deployed the web application, then compiled TestPlugin into a .class file and dropped it into the designated folder. I called a web service that hits runPluginFromDropBox() with the class name and got the expected output.

This all worked as a proof of concept, but my plugin is effectively useless unless it can be made aware of my web application's classes. I've since read that .war is intended only as a standalone application, and not meant to be on other libraries' classpaths, which doesn't bode well for this little side-project.

I had a look at this discussion: Extending Java Web Applications with plugins and get the feeling I'm wading into a swamp of design challenges for no huge reason and should turn around. However that post is kind of old and is Tomcat-specific, so I just thought I'd ask if there's any straightforward way for me to approach this without some elaborate third party framework.


The classes of a war file are loaded by a specific classloader, to isolate the war from other webapps deployed on the same server, and to be able to undeploy the war.

To be aware of the webapp classes, your plugin classloader should have the webapp classloader as its parent. I'm not aware of all the problems you might have by using an additional classloader, but I suspect you might have memory leaks and other nasty problems (static values kept in memory, etc.) when the container will undeploy and redeploy the webapp. And you might have differences between containers as well.

0

精彩评论

暂无评论...
验证码 换一张
取 消