как сделать динамически загружаемый плагин осведомленным о веб-приложении - PullRequest
1 голос
/ 28 августа 2011

Я решил реализовать динамическую загрузку классов в моем веб-приложении glassfish, чтобы испытать его и поддерживать небольшие плагины, которые могут загружаться и выполняться веб-приложением во время выполнения.

Я добавил следующий класс:

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");
   }
}

Я развернул веб-приложение, затем скомпилировалTestPlugin в файл .class и поместите его в указанную папку.Я вызвал веб-сервис, который набрал runPluginFromDropBox() с именем класса и получил ожидаемый результат.

Все это работало как подтверждение концепции, но мой плагин фактически бесполезен, если его не проинформировать о моей сети.классы приложений.С тех пор я читал, что .war предназначен только как отдельное приложение и не предназначен для использования в пути классов других библиотек, что не сулит ничего хорошего для этого небольшого побочного проекта.

У меня былпосмотрите на это обсуждение: Расширение веб-приложений Java с помощью плагинов и у меня возникло ощущение, что я без особых на то оснований сталкиваюсь с множеством проблем проектирования и должен обернуться.Однако этот пост довольно старый и специфичен для Tomcat, поэтому я просто подумал, что могу спросить, есть ли какой-нибудь простой способ подойти к этому без какой-либо сложной сторонней структуры.

1 Ответ

2 голосов
/ 28 августа 2011

Классы файла войны загружаются определенным загрузчиком классов, чтобы изолировать войну от других веб-приложений, развернутых на том же сервере, и иметь возможность отменить развертывание войны.

Чтобы знать о классах веб-приложений, ваш плагин classloader должен иметь загрузчик классов веб-приложений в качестве его родителя.Я не знаю всех проблем, которые могут возникнуть при использовании дополнительного загрузчика классов, но я подозреваю, что у вас могут возникнуть утечки памяти и другие неприятные проблемы (статические значения, хранящиеся в памяти и т. Д.), Когда контейнер будет развернут и повторно развернут webapp.И у вас могут быть различия между контейнерами.

...