Возможно ли, чтобы системный загрузчик классов загружал файлы .class, указанные во время выполнения?

StackOverflow https://stackoverflow.com/questions/1873916

Вопрос

Я пишу инструмент статического анализа для назначения, он анализирует байт-код Java с использованием библиотеки ASM.Одна из частей ASM, которую мы используем, требует (или, по крайней мере, кажется, что требует), чтобы класс был загружен из ClassLoader.

Мы надеялись, что инструмент сможет анализировать файлы .class, не требуя их указания в classpath .Мы уже загружаем .classes из указанного каталога во время выполнения и считываем их с помощью InputStream .Это приемлемо для ASM в большинстве случаев.Есть несколько классов, таких как SimpleVerifier, которые, однако, пытаются загрузить классы.

Возможно ли в этом сценарии зарегистрировать файлы .class для загрузки, чтобы вызовы Class.forName() будете ли загружать их?Или есть простой способ расширить ClassLoader, чтобы разрешить это?


Редактировать:информация о URLClassLoader было полезно.К сожалению, используя Thread.currentThread().setContextClassLoader() к примеру, это не сработало в данном сценарии.Библиотечный код, в который я взываю, использует загрузчик, который он извлекает при инициализации экземпляра, используя getClass().getClassLoader().

К тому времени, когда я установил URLClassLoader, класс еще не был инициализирован, поэтому я предполагаю, что contextClassLoader не загружает этот класс.

Правильно ли я понял ответы?Возможно ли использование URLClassLoader для загрузки стороннего класса?

Это было полезно?

Решение

Почти.

Если у вас где-то есть классы, скомпилированные, вы можете загрузить их с помощью Загрузчик URLCLASSS.Затем вы можете установить этот загрузчик классов в качестве загрузчика классов для текущего потока: Thread.setContextClassLoader(загрузчик классов)

Пользователи могут получить загрузчик текущего класса контекста потоков и использовать его для доступа к определению класса.

Другие советы

Прежде всего, ASM можно использовать таким образом, чтобы он не использовал ClassLoader для получения информации о классах.

В ASM framework есть несколько мест, где он загружает классы по умолчанию, но все эти места могут быть переопределены в ваших собственных подклассах.Из глубины моей головы:

  • ClassWriter.getcommon суперкласс() метод вызывается только тогда, когда ClassWriter.Используется флаг COMPUTE_FRAMES, который можно перезаписать, чтобы не использовать ClassLoader для получения информации о классах.Вы можете найти пример этого в ClassWriterComputeFramesTest - класс , вычислительный фреймтест это вводит абстракцию ClassInfo
  • Аналогично метод SimpleVerifier.getClass() используется SimpleVerifier.Присваивается из() и вы можете перезаписать последнее и использовать абстракцию ClassInfo для поиска общего супертипа.Если я не ошибаюсь, проект AspectWerkz реализовал аналогичную вещь в своем коде сопоставления с шаблоном типа.Также обратите внимание, что существует SimpleVerifier.setClassLoader() метод, который вы можете использовать, если вы все еще хотите загружать свои собственные классы.

Кстати, в JVMS Sun загруженные классы попадают в область PermGen и не могут быть выгружены, поэтому не стоит загружать классы только для целей статического анализа кода, если вы можете избежать этого, особенно если инструмент будет интегрирован в долговременный процесс, такой как IDE.

Насколько я знаю, вы не можете расширить загрузчик системных классов во время выполнения, но вы можете динамически загружать классы из произвольного местоположения (jar или каталога), используя Загрузчик URLCLASSS.

Вы могли бы попробовать настроить "лаунчер" при запуске вашего приложения, который создает URLClassLoader передавая ему местоположения в classpath и свой собственный .class расположения и запустите приложение из этого загрузчика классов.

Когда в SimpleVerifier загружается с помощью URLClassLoader он также сможет загружать классы из дополнительных местоположений.

Да, вы можете использовать Загрузчик URLCLASSS

У меня есть тест, в котором я загружаю класс во время выполнения.Этого класса нет в classpath (и даже не существует при запуске теста, если уж на то пошло), позже он загружается и отлично работает.

Вот код.

void testHello() throws MalformedURLException, ClassNotFoundException {
    URL[] url = {
            new URL("file:/home/oreyes/testwork/")
    };

    try {
        new URLClassLoader(url).loadClass("Hello");
        throw new AssertionError("Should've thrown ClassNotFoundException");
    } catch ( ClassNotFoundException cnfe ){}


    c.process();// create the .class file 

    new URLClassLoader(url).loadClass("Hello");

    // it works!!
}

Взято из этого вопрос.

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

 /**
 * Used to hold the bytecode for the class to be loaded.
 */
private final static ThreadLocal<byte[]> BYTE_CODE = new ThreadLocal<byte[]>();

@Override
protected Class<?> findClass(final String name) throws ClassNotFoundException {
    final byte[] bytes = BYTE_CODE.get();
    if (null == bytes) {
        throw new ClassNotFoundException(name);
    }
    return this.defineClass(null, bytes, 0, bytes.length);
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top