Автор оригинала: Scott Robinson.
Java-не самый динамичный язык в мире, но при некотором тщательном планировании и гибкости вы можете сделать свои программы немного более динамичными, загружая классы во время выполнения.
Это может быть полезно, когда вы хотите сделать свое приложение более расширяемым и разрешить замену определенных модулей в нем, просто поместив jar, реализующий интерфейс, в каталог.
Или вы можете загрузить написанные пользователем плагины во время выполнения. Например, это может быть полезно для добавления функциональности в веб-приложение. Добавление плагина может позволить вам изменить способ аутентификации пользователя или улучшить ведение журнала.
Код
Вот некоторый код, который поможет вам динамически загружать новый класс с учетом пути к его файлу jar.
import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; public class ExtensionLoader{ public C LoadClass(String directory, String classpath, Class parentClass) throws ClassNotFoundException { File pluginsDir = new File(System.getProperty("user.dir") + directory); for (File jar : pluginsDir.listFiles()) { try { ClassLoader loader = URLClassLoader.newInstance( new URL[] { jar.toURL() }, getClass().getClassLoader() ); Class> clazz = Class.forName(classpath, true, loader); Class extends C> newClass = clazz.asSubclass(parentClass); // Apparently its bad to use Class.newInstance, so we use // newClass.getConstructor() instead Constructor extends C> constructor = newClass.getConstructor(); return constructor.newInstance(); } catch (ClassNotFoundException e) { // There might be multiple JARs in the directory, // so keep looking continue; } catch (MalformedURLException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } } throw new ClassNotFoundException("Class " + classpath + " wasn't found in directory " + System.getProperty("user.dir") + directory); } }
Использование кода:
ExtensionLoaderloader = new ExtensionLoader (); somePlugin = loader.LoadClass("path/to/jar/file", "com.example.pluginXYZ", MyPlugin.class);
Несколько Заметок
Безусловно, есть лучшие способы сделать приложение расширяемым ( OSGi , Портлеты , JPF и т.д.), Но иногда вам просто нужно что-то простое, как это.
Обратите внимание, что ExtensionLoader
вызывает только конструкторы без аргументов (классы, подобные бобам). Возможно, было бы более полезно вернуть Конструктор расширяет класс C>
и вызывает его с соответствующими аргументами. Если это так, убедитесь, что вы загрузили правильный конструктор из метода new Class.getConstructor ()
. расширяет класс C>
ВНИМАНИЕ: В этом коде не проводится проверка безопасности, поэтому убедитесь, что вы доверяете загружаемым классам!