Необходимо заменить существующий класс во время выполнения динамически сгенерированным и скомпилированным java .classfile во время выполнения.

Моя цель - динамически вводить новые атрибуты + методы установки геттера в определение класса во время выполнения. В настоящее время у меня есть метод для регенерации кода с добавленными атрибутами, которые затем скомпилируют сгенерированный код.

Первоначально у меня будет шаблон для каждого класса во время компиляции. После запуска проекта класс шаблона загружается во время выполнения. Я написал некоторый код для динамической генерации java-кода и его компиляции. Когда я загружаю только что созданный класс, используя приведенный ниже код, я не могу получить доступ к внедренным методам. Я думаю, что не могу перезаписать существующее определение среды выполнения. Я просмотрел много блогов, но все еще не мог понять, почему. Пожалуйста помоги.

Я получаю доступ к недавно добавленным методам в DROOLS, и на них нет ссылок ни в одном другом классе, который может вызвать проблемы во время компиляции. Правила обработчика правил с новыми атрибутами обновляются во время выполнения, поэтому мне необходимо соответствующим образом адаптировать свой код. Ниже приведен код ClassLoader. Этот код не генерирует никаких исключений, но не может решить мою задачу. Не уверен, что кодировка правильная.

public static boolean loadClass2RunTime() {
    try {
        File folder = new File("target");
        File dir = new File(folder, "com/itap/template");
        File[] classFiles = dir.listFiles();
        URL[] url = new URL[] { folder.toURI().toURL() };

        int i = 0;
        for (File classFile : classFiles) {
            if (classFile.getName().matches(".*\\.class")) {
                System.out.println(classFile.getName().substring(0,
                        classFile.getName().lastIndexOf(".")));

                ClassLoader loader = URLClassLoader
                        .newInstance(new URL[] { folder.toURI().toURL() });

                Class cls = loader.loadClass("com.itap.template."
                        + classFile.getName().substring(0,
                                classFile.getName().lastIndexOf(".")));
                ClassLoader temp = cls.getClassLoader();
            }
        }

        return true;

    } catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (MalformedURLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return false;
}

person Chandu    schedule 16.06.2014    source источник
comment
Это похоже на проблему XY. Если я понимаю ваши требования, Groovy ExpandoMetaClass должен делать то, что вы хотите.   -  person chrylis -cautiouslyoptimistic-    schedule 16.06.2014


Ответы (1)


URLClassLoader может быть полезен, когда вам нужно загрузить вновь созданные классы во время выполнения. К сожалению, вы не сможете перезагрузить определение уже загруженного класса (т.е. перезагрузить класс) с помощью URLCLassLoader.

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

URLClassLoader проверит, был ли уже загружен указанный класс. Если он найден, он просто возвращает экземпляр, указывающий на загруженный класс. Таким образом, вы не сможете перезаписать существующее определение среды выполнения.

Решение. Стандартный подход к поддержке динамической перезагрузки класса в Java заключается в том, чтобы прочитать информацию о байтах класса (из его файла .class) и написать собственный загрузчик классов для загрузки класса с использованием этой информации о байтах. .

Что следует помнить при использовании пользовательского ClassLoader:

  • Чтобы перезагрузить класс, существующий экземпляр ClassLoader (который загрузил класс) и все загруженные экземпляры класса должны быть удалены сборщиком мусора.
  • Пользовательский ClassLoader должен загружать только определенные классы (которые необходимо загрузить/перезагрузить). Запрос на загрузку всех остальных классов (встроенных классов Java или классов из других пакетов) должен быть делегирован загрузчику родительского класса. Попытка загрузить встроенные системные классы может привести к исключению привилегий.

Шаги, которым следует загрузчик классов при загрузке классов:

  1. Проверьте, был ли уже загружен класс.
  2. Если он не загружен, попросите загрузчик родительского класса загрузить класс.
  3. Если загрузчик родительского класса не может загрузить класс, попытайтесь загрузить его в этот загрузчик классов.

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

Вот пример ссылки, которая может помочь вам разработать собственный загрузчик классов на Java. http://www.javablogging.com/java-classloader-2-write-your-own-classloader/
http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html

Отредактировано после вашего комментария:

Я думаю, что оператор InputStream stream = getClass().getClassLoader().getResourceAsStream(name); функции loadClassData в примере не подбирает последнюю версию класса.

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

Вы можете скорее использовать,

FileInputStream stream = new FileInputStream("Path to your class file");
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int data = stream.read();

while(data != -1){
    buffer.write(data);
    data = stream.read();
}

stream.close();

byte[] classData = buffer.toByteArray();

чтобы прочитать информацию о байтах для класса и попытаться загрузить ее, используя вашу версию ClassLoader (пользовательский ClassLoader).

person Ankur Shanbhag    schedule 16.06.2014
comment
Я прошел по предоставленным ссылкам, и концепция ясна. Мне нужно изменить последовательность загрузки классов, написав свой собственный загрузчик классов. Я использовал тот же код, что и в javablogging.com/java- classloader-2-write-your-own-classloader с некоторыми изменениями в соответствии с моим требованием. Даже тогда последняя версия класса не загружается. Насколько я понимаю, я думаю, что оператор InputStream stream = getClass().getClassLoader().getResourceAsStream(name); функции loadClassData в примере не подбирает последнюю версию класса. Посоветуйте, если я что-то упускаю. - person Chandu; 18.06.2014
comment
@Chandu: я изменил сообщение после вашего комментария. Посмотри на это. Посмотрите, поможет ли это. - person Ankur Shanbhag; 18.06.2014