Пример: загрузка класса Java во время выполнения

Java - не самый динамичный язык, но при тщательном планировании и гибкости вы можете сделать свои программы немного более динамичными, загрузив классы во время выполнения. Это может быть полезно, когда вы хотите сделать свое приложение более расширяемым и разрешить замену определенных модулей в нем, просто отбросив jar, реализующий интерфейс, в каталог. Или вы можете загрузить написанные пользователем плагины [http://www.javaranch.com/journal/200607/Plugins.html] во время выполнения. Например, это mi

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<C> { 
 
 public C LoadClass(String directory, String classpath, Class<C> 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); 
 } 
 } 

Использование кода:

 ExtensionLoader<MyPlugin> loader = new ExtensionLoader<MyPlugin>(); 
 somePlugin = loader.LoadClass("path/to/jar/file", "com.example.pluginXYZ", MyPlugin.class); 

Некоторые примечания

Конечно, есть более эффективные способы сделать приложение расширяемым ( OSGi , Portlets , JPF и т. Д.), Но иногда вам просто нужно что-то такое простое.

Обратите внимание, что ExtensionLoader вызывает только конструкторы без аргументов (классы, подобные bean-компонентам). Может быть более выгодно вернуть Constructor<? extends C> и вызывает его с соответствующими аргументами. В этом случае убедитесь, что вы загружаете правильный конструктор из newClass.getConstructor() .

ВНИМАНИЕ! В этом коде не выполняется никаких проверок безопасности, поэтому убедитесь, что вы доверяете загружаемым классам!

comments powered by Disqus

Содержание