Анализ библиотек байт-кода
Как я могу сказать из ответов, которые вы получили здесь, и ответов на вопросы, которые вы рассмотрели, эти ответы формально не рассматривают вопрос в той явной форме, которую вы указали. Вы просили сравнения, между тем в этих ответах смутно указано, чего можно было бы хотеть, исходя из вашей цели (например, вам нужно знать байт-код? [Y / n]), или они слишком узкие.
Этот ответ представляет собой краткий анализ каждой структуры байт-кода и обеспечивает быстрое сравнение в конце.
- Крошечный (javassist.jar (3.21.0) составляет ~ 707 КБ / javassist-rel
Modifier.PUBLIC
22_0_cr1.zip составляет ~ 1,5 МБ)
- Высокий (/ Низкий) -уровень
- Простой
- Полная функция
- Требуется минимальное или нулевое знание формата файла класса
- Требуется умеренное знание набора инструкций Java
- Минимальные усилия по обучению
- Имеет некоторые особенности однострочных / многострочных методов компиляции и вставки байт-кода.
Лично я предпочитаю Javassist просто из-за того, как быстро вы сможете его использовать, а также создавать классы и управлять ими. учебник прост и понятен. Размер файла jar составляет крошечные 707 КБ, поэтому он удобен и портативен; делает его пригодным для автономных приложений.
ASM от ObjectWeb - это очень обширная библиотека, в которой нет ничего, связанного с построением, генерацией и загрузкой классов. Фактически, у него даже есть инструменты анализа классов с предопределенными анализаторами. Считается, что это промышленный стандарт для обработки байт-кода. Это также причина, по которой я избегаю этого.
Когда я вижу примеры ASM, мне кажется, что это громоздкая задача с количеством строк, необходимых для изменения или загрузки класса. Даже некоторые параметры некоторых методов кажутся немного загадочными и неуместными для Java. С такими вещами, как ACC_PUBLIC
и множеством вызовов методов с null
повсюду, честно говоря, похоже, что он лучше подходит для низкоуровневого языка, такого как C. Почему бы просто не передать строковый литерал, такой как "public" или перечисление Modifier.PUBLIC
? Он более дружелюбный и простой в использовании. Однако это мое мнение.
Для справки, вот руководство по ASM (4.0): https://www.javacodegeeks.com/2012/02/manipulating-java-class-files-with-asm.html
- Маленький (bcel-6.0-bin.zip составляет 7,3 МБ / bcel-6.0-src.zip составляет 1,4 МБ)
- Низкий уровень
- Адекватный
- Выполняет свою работу
- Требуется знание набора инструкций Java
- Легко учить
Из того, что я видел, эта библиотека является вашей базовой библиотекой классов, которая позволяет вам делать все, что вам нужно, если вы можете сэкономить несколько месяцев или лет.
Вот учебник BCEL, который действительно разъясняет это: http://www.geekyarticles.com/2011/08/manipulating-java-class-files-with-bcel.html?m=1
Несмотря на то, что вы можете читать информацию из классов и что вы можете преобразовывать классы, библиотека кажется адаптированной для прокси. учебник посвящен bean-компонентам для прокси, и в нем даже упоминается, что он используется с помощью «фреймворков доступа к данным для создания динамических прокси-объектов и перехвата доступа к полям». Тем не менее, я не вижу причин, по которым вы не можете использовать его для более простых целей манипулирования байт-кодом вместо прокси.
- Маленькая корзина / "Огромный" источник (для сравнения) (byte-buddy-dep-1.8.12.jar составляет ~ 2,72 МБ / 1.8.12 (zip) составляет 124,537 МБ (точно))
- Зависит от ASM
- Высокий уровень
- Полная функция
- Лично своеобразное имя для класса Service Pattern (ByteBuddy.class)
- Требуется мало или совсем не требуется знаний байтового кода Java
- Легко учить
Короче говоря, там, где BCEL не хватает, ByteBuddy в изобилии. Он использует первичный класс ByteBuddy с использованием шаблона проектирования служб. Вы создаете новый экземпляр ByteBuddy, и он представляет класс, который вы хотите изменить. Когда вы закончите свои модификации, вы можете сделать DynamicType
с make()
.
На их веб-сайте есть полное руководство с документацией по API. Цель вроде бы для модификаций довольно высокого уровня. Когда дело доходит до методов, в официальном или стороннем учебном пособии нет ничего о создании метода с нуля, кроме делегирования метода (EDITME, если вы знаете, где это объясняется).
Их руководство можно найти здесь, на их веб-сайте. Некоторые примеры можно найти здесь.
У меня есть собственная библиотека байт-кода, которую я создаю, которая будет называться Java Class Assistant, или для краткости jCLA, из-за другого проекта, над которым я работаю, и из-за указанных причуд с Javassist , но я не буду ее выпускать в GitHub, пока он не будет завершен, но проект в настоящее время доступен для просмотра на GitHub и предоставления отзывов, поскольку он в настоящее время находится в альфа-версии, но все еще достаточно работоспособен, чтобы быть базовой библиотекой классов (в настоящее время работает над компиляторами; пожалуйста, помогите меня, если сможешь! Он выйдет намного раньше!).
Это будет довольно просто с возможностью чтения и записи файлов классов в файл JAR и из него, а также с возможностью компилировать и декомпилировать байт-код в исходный код и файлы классов и из них.
Общий шаблон использования упрощает работу с jCLA, , хотя может потребоваться некоторое привыкание к и, по-видимому, очень похож на ByteBuddy по стилю методов и параметрам методов для модификаций классов:
import jcla.ClassPool;
import jcla.ClassBuilder;
import jcla.ClassDefinition;
import jcla.MethodBuilder;
import jcla.FieldBuilder;
import jcla.jar.JavaArchive;
import jcla.classfile.ClassFile;
import jcla.io.ClassFileOutputStream;
public class JCLADemo {
public static void main(String... args) {
// get the class pool for this JVM instance
ClassPool classes = ClassPool.getLocal();
// get a class that is loaded in the JVM
ClassDefinition classDefinition = classes.get("my.package.MyNumberPrinter");
// create a class builder to modify the class
ClassBuilder clMyNumberPrinter= new ClassBuilder(classDefinition);
// create a new method with name printNumber
MethodBuilder printNumber = new MethodBuilder("printNumber");
// add access modifiers (use modifiers() for convenience)
printNumber.modifier(Modifier.PUBLIC);
// set return type (void)
printNumber.returns("void");
// add a parameter (use parameters() for convenience)
printNumber.parameter("int", "number");
// set the body of the method (compiled to bytecode)
// use body(byte[]) or insert(byte[]) for bytecode
// insert(String) also compiles to bytecode
printNumber.body("System.out.println(\"the number is: \" + number\");");
// add the method to the class
// you can use method(MethodDefinition) or method(MethodBuilder)
clMyNumberPrinter.method(printNumber.build());
// add a field to the class
FieldBuilder HELLO = new FieldBuilder("HELLO");
// set the modifiers for hello; convenience method example
HELLO.modifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL);
// set the type of this field
HELLO.type("java.lang.String");
// set the actual value of this field
// this overloaded method expects a VariableInitializer production
HELLO.value("\"Hello from \" + getClass().getSimpleName() + \"!\"");
// add the field to the class (same overloads as clMyNumberPrinter.method())
clMyNumberPrinter.field(HELLO.build());
// redefine
classDefinition = clMyNumberPrinter.build();
// update the class definition in the JVM's ClassPool
// (this updates the actual JVM's loaded class)
classes.update(classDefinition);
// write to disk
JavaArchive archive = new JavaArchive("myjar.jar");
ClassFile classFile = new ClassFile(classDefinition);
ClassFileOutputStream stream = new ClassFileOutputStream(archive);
try {
stream.write(classFile);
} catch(IOException e) {
// print to System.out
} finally {
stream.close();
}
}
}
(для вашего удобства производственная спецификация VariableInitializer. < / а>)
Как можно понять из приведенного выше фрагмента, каждый ClassDefinition
неизменяем. Это делает jCLA более безопасным, поточно-ориентированным, сетевым и простым в использовании. Система вращается в первую очередь вокруг ClassDefinitions как объекта выбора для запроса информации о классе на высоком уровне, и система построена таким образом, что ClassDefinition преобразуется в целевые типы, такие как ClassBuilder и ClassFile, и обратно.
jCLA использует многоуровневую систему для данных классов. Внизу у вас есть неизменное ClassFile
: структура или программное представление файла класса. Затем у вас есть неизменяемые ClassDefinition
, которые конвертируются из ClassFiles во что-то менее загадочное, более управляемое и полезное для программиста, который модифицирует или считывает данные из класса, и сравнимо с информацией, доступной через java.lang.Class
. Наконец, у вас есть изменяемые ClassBuilder
s. ClassBuilder - это то, как классы изменяются или создаются. Это позволяет вам создавать ClassDefinition
прямо из построителя из его текущего состояния. Создавать новый конструктор для каждого класса не обязательно, поскольку метод reset()
очистит переменные.
(Анализ этой библиотеки будет доступен, как только она будет готова к выпуску.)
Но до тех пор, на сегодняшний день:
- Маленький (src: 227,704 КБ, точно, 02.06.2018)
- Самодостаточный (без зависимостей, кроме поставляемой библиотеки Java)
- Высокий уровень
- Не требуется знания байт-кода Java или файлов классов (для API уровня 1, например, ClassBuilder, ClassDefinition и т. Д.)
- Легко учиться (даже проще, если исходить из ByteBuddy)
Однако я все же рекомендую изучить байт-код Java. Это упростит отладку.
Сравнение
Учитывая все эти анализы (за исключением jCLA на данный момент), самой широкой структурой является ASM, самым простым в использовании является Javassist, самой базовой реализацией является BCEL, а самым высокоуровневым для генерации байт-кода и прокси является cglib.
ByteBuddy заслуживает отдельного объяснения. Его легко использовать, как Javassist, но, похоже, ему не хватает некоторых функций, которые делают Javassist отличным, таких как создание методов с нуля, поэтому вам, очевидно, придется использовать ASM для этого. Если вам нужно сделать небольшую модификацию с классами, ByteBuddy - это то, что вам нужно, но для более продвинутой модификации классов при сохранении высокого уровня абстракции лучше выбрать Javassist.
Примечание: если я пропустил библиотеку, отредактируйте этот ответ или упомяните его в комментарии.
person
AMDG
schedule
26.08.2017