Я решил реализовать динамическую загрузку классов в моем веб-приложении 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, поэтому я просто подумал, что могу спросить, есть ли какой-нибудь простой способ подойти к этому без какой-либо сложной сторонней структуры.