Анализ библиотек байт-кодов
Как я могу судить по ответам, которые вы получили здесь, и ответам на вопросы, на которые вы смотрели, эти ответы формально не отвечают на вопрос в явном виде, который вы сформулировали.Вы просили провести сравнение, в то время как в этих ответах смутно указывалось, что можно получить, исходя из цели (например, вам нужно знать байт-код? [Y / n]), или они слишком узкие.
ЭтоОтвет представляет собой краткий анализ каждой структуры байт-кода и обеспечивает быстрое сравнение в конце.
- Tiny ( javassist.jar (3.21.0) равно ~ 707 КБ / javassist-rel_3_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
- Очень маленький ( cglib-3.2.5.jar равен 295 КБ / исходный код )
- Зависит от ASM
- Высокий уровень
- Полнофункциональный (Генерация байт-кода)
- Требуется мало или нет знаний о байт-коде Java
- Легко учиться
- Эзотерическая библиотека
Несмотря на то, что вы можете читать информацию из классов и что вы можете преобразовывать классы, библиотека, похоже, приспособлена для прокси.Учебное пособие полностью посвящено компонентам для прокси-серверов и даже упоминает о том, что оно используется "структурами доступа к данным для создания динамических прокси-объектов и перехвата доступа к полям".Тем не менее, я не вижу причин, по которым вы не можете использовать его для более простой цели манипулирования байт-кодом вместо прокси.
- Маленькая корзина / "Огромный" источник (для сравнения) ( 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
s, которые преобразуются из ClassFiles в нечто менее загадочное, более управляемое и полезное для программиста, который модифицирует или читает данные из класса, и сравнимо с информацией, доступ к которой осуществляется через java.lang.Class
.Наконец, у вас есть изменяемые ClassBuilder
с.ClassBuilder - это то, как классы модифицируются или создаются.Это позволяет вам создавать ClassDefinition
непосредственно из компоновщика из его текущего состояния.Создание нового компоновщика для каждого класса не требуется, поскольку метод reset()
очистит переменные.
(Анализ этой библиотеки будет доступен, как только она будет готова к выпуску.)
Но до тех пор, по состоянию на сегодняшний день:
- Маленький (источник: 227,704 КБ точный, 02/2/2018)
- Самодостаточный (никаких зависимостей, кроме поставляемой библиотеки Java)
- High-level
- Не требуется знание байт-кода Java или файлов классов (для API уровня 1, например, ClassBuilder, ClassDefinition и т. Д.)
- Легко учиться (даже легче, еслиисходящий от ByteBuddy)
Я все же рекомендую узнать о байт-коде Java, однако.Это облегчит отладку.
Сравнение
Учитывая все эти анализы (за исключением jCLA на данный момент), самой широкой платформой является ASM, самой простой в использовании является Javassist, самой базовойРеализация - BCEL, а самый высокий уровень генерации байт-кода и прокси - cglib.
ByteBuddy заслуживает своего объяснения.Он прост в использовании, как Javassist, но, похоже, ему не хватает некоторых функций, которые делают Javassist великолепным, таких как создание методов с нуля, поэтому вам, очевидно, придется использовать ASM для этого.Если вам нужно сделать небольшую модификацию с классами, лучше использовать ByteBuddy, но для более продвинутой модификации классов при сохранении высокого уровня абстракции лучше выбрать Javassist.
Примечание: если я пропустилБиблиотека, пожалуйста, отредактируйте этот ответ или упомяните его в комментарии.