Рубрики
Без рубрики

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

Автор оригинала: 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 newClass = clazz.asSubclass(parentClass);
        // Apparently its bad to use Class.newInstance, so we use 
        // newClass.getConstructor() instead
        Constructor 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 loader = new ExtensionLoader();
somePlugin = loader.LoadClass("path/to/jar/file", "com.example.pluginXYZ", MyPlugin.class);

Несколько Заметок

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

Обратите внимание, что ExtensionLoader вызывает только конструкторы без аргументов (классы, подобные бобам). Возможно, было бы более полезно вернуть Конструктор расширяет класс C> и вызывает его с соответствующими аргументами. Если это так, убедитесь, что вы загрузили правильный конструктор из метода new Class.getConstructor () . расширяет класс C>

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