Java: автоматический пользовательский загрузчик классов

#java #classloader #urlclassloader

#java #загрузчик классов #urlclassloader

Вопрос:

Мое приложение использует стандартный набор инструментов виджетов (SWT) для своего графического интерфейса. Моя проблема в том, что 32-разрядная библиотека SWT не работает на 64-разрядной JVM. Но я не хочу заставлять людей выбирать правильную архитектуру при получении программного обеспечения. Итак, я хочу объединить обе 32-разрядные и 64-разрядные библиотеки и автоматически определять архитектуру во время выполнения. Я обнаружил, что могу получить правильную архитектуру JVM следующим образом:

 if (System.getProperty("os.arch").contains("64")) {
    // ...
}
  

Теперь все, что осталось, это загрузить jar. Но проблема в том, что все примеры, которые я нашел, требуют, чтобы вы вручную загружали класс перед его использованием.

 Class.forName("MyClass", false, myClassLoader);
  

Итак, мой вопрос в том, возможно ли «зарегистрировать» мой загрузчик классов, чтобы мне не приходилось загружать классы заранее?


Обновление: я создал свой собственный дочерний класс URLClassLoader и установил его в качестве загрузчика классов по умолчанию с аргументом командной строки -Djava.system.class.loader ; но я получаю эту ошибку:

 Error occurred during initialization of VM
java.lang.Error: java.lang.NoSuchMethodException: com.program.LibraryLoader.<init>(java.lang.ClassLoader)
    at java.lang.ClassLoader.initSystemClassLoader(Unknown Source)
    at java.lang.ClassLoader.getSystemClassLoader(Unknown Source)
  

Я думаю, LibraryLoader.<init> относится к конструктору… но он есть ( public LibraryLoader(URI[] urls) ).


Обновление 2: Почти готово, JVM запускается сейчас. Я добавил этот конструктор, чтобы заставить его работать:

 public LibraryLoader(ClassLoader classLoader) {
    super(new URL[0], classLoader);
}
  

Но после добавления jar с помощью addPath() ( file:lib/jars/swt.jar ) он выдает только NoClassDefFoundError . Да, я дважды проверил, существует ли файл.

Ответ №1:

Вы могли бы попытаться внедрить свой пользовательский загрузчик классов с помощью свойства «java.system.class.loader» (см. ClassLoader#getSystemClassLoader). Тем не менее, я бы рекомендовал использовать OSGi и позволить фреймворку выполнять сложные задачи.

Комментарии:

1. Если я введу его с помощью java.system.class.loader , будут ли другие классы по-прежнему загружены по умолчанию ClassLoader ?

2. Вам нужно будет убедиться, что ваш собственный загрузчик классов делегирует его родительскому для любого класса, отличного от swt.

3. Хорошо, я нашел здесь еще немного информации: coderanch.com/t/384068/java/java/Adding-JAR-file-Classpath-at . Как мне установить это свойство ( java.system.class.loader ) перед запуском программы?

4. Вы можете задать системное свойство, добавив следующий аргумент командной строки: -Djava.system.class.loader=com.mycompany. MyClassLoader . Обратите внимание, что этот аргумент должен быть установлен перед вашими собственными аргументами программы (если таковые имеются), но после содержимого Xmx / Xms.

5. Могу ли я установить это в МАНИФЕСТЕ? Если да, то каким образом?

Ответ №2:

Как часть конструктора для вашего пользовательского загрузчика классов, вызовите definePackage с соответствующей информацией, с URL-адресом, указывающим на желаемый файл jar.

Этот пример показывает, что пользовательский загрузчик классов вызывается, когда я пытаюсь создать экземпляр класса из swing, потому что я определил свой загрузчик классов как загрузчик этого пакета.

 import java.net.URL;

public class junk extends ClassLoader {

  byte[] dummy = new byte[0];

  public static void main(String[] args) throws Exception {
    new junk();

    new javax.swing.JPanel();

  }

  public junk() throws Exception {
    definePackage("javax.swing","","","","","","",new URL("file://junk.class"));
  }

  public Class<?> findClass(String s) throws java.lang.ClassNotFoundException{
    Class<?> retVal = super.findClass(s);

    System.out.println("delegated responsibility for " s " to superclass");

    return retVal;
  }

  public Package getPackage(String s) {
    Package retVal = super.getPackage(s);

    System.out.println("delegated responsibility for " s " to superclass");

    return retVal;
  }

}
  

Результат:

делегированная ответственность за javax.swing для суперкласса