Есть ли альтернативы cglib? [закрытый]


просто из любопытства, есть ли какие-либо (стабильные) проекты с открытым исходным кодом для генерации кода java во время выполнения, кроме cglib? И почему я должен их использовать?

5 54

5 ответов:

ПКРjava-asm

CGLIB и почти все другие библиотеки построены поверх ASM, который сам действует на очень низком уровне. Это шоу-стопор для большинства людей, так как вы должны понимать байтовый код и немного виртуальные машины использовать его правильно. Но освоение ASM, безусловно, очень интересно. Обратите внимание, однако, что в то время как есть большойASM 4 guide, в некоторой части API документация javadoc может быть очень краткой, если она вообще присутствует, но она улучшается. Он внимательно следит за версиями JVM для поддержки новых функций.

однако, если вам нужен полный контроль, ASM - это ваше оружие выбора.

этот проект видит регулярные обновления ; на момент этого редактирования версия 5.0.4 была выпущена 15 мая 2015 года.

Byte Buddy byte-buddy

Byte Buddy-это довольно новая библиотека, но предоставляет любую функциональность, которую предоставляет CGLIB или Javassist и многое другое. Byte Buddy может быть полностью настроен до уровня байтового кода и поставляется с выразительным доменным языком, который позволяет очень читаемый код.

  • он поддерживает все версии байт-кода JVM, включая семантические изменения Java 8 некоторых опкодов относительно методов по умолчанию.
  • ByteBuddy, похоже, не страдает от недостатков других библиотек
  • высоко настраиваемый
  • довольно быстро (benchmarkкод)
  • тип safe fluent API
  • введите безопасные обратные вызовы

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

  • Аннотация управляемые (гибкие)

    пользовательские обратные вызовы могут быть сконфигурированы с аннотациями, позволяющими получать нужные параметры в обратном вызове.

  • доступно в качестве агента

    nifty agent builder позволяет использовать ByteBuddy в качестве чистого агента или в качестве агента присоединения. Это позволяет различный вид

  • очень хорошо документально
  • много пример
  • Чистый код, ~94% тестового покрытия
  • поддержка Android DEX

основной недостаток возможно, API будет немного подробным для новичка, но он разработан как API выбора в форме DSL поколения прокси ; нет никакой магии или сомнительных значений по умолчанию. При работе с байтовым кодом это, пожалуй, самый безопасный и разумный выбор. Также с несколькими примерами и большим учебником это не так реальная проблема.

в октябре 2015 года этот проект получил Oracle Duke's choice award. В это время он просто достиг 1.0.0 milestone, что является большим достижением.

отметим, что mockito сменил CGLIB by Byte Buddy в версии 2.1.0.

Javassistjavassist

javadoc Javassist намного лучше, чем у CGLIB. API Class engineering в порядке, но Javassist также не идеален. В частности,ProxyFactory что является эквивалентом CGLIB Enhancer страдают от некоторых недостатков тоже, просто перечислить несколько :

  • метод моста не полностью поддерживается (т. е. тот, который генерируется для ковариантных возвращаемых типов)
  • ClassloaderProvider - Это статическое поле, а затем оно применяется ко всем экземплярам в одном загрузчике классов
  • пользовательские имена можно было бы приветствовать (с чеками для подписанных банок)
  • нет точки расширения, и почти все методы интереса являются частными, что является громоздким, если мы хотим изменить какое-то поведение
  • хотя Javassist предлагает поддержку атрибутов аннотаций в классах, они не поддерживаются в ProxyFactory.

на аспектно-ориентированной стороне можно ввести код в прокси, но этот подход в Javassist ограничен и немного подвержен ошибкам:

  • аспект код записывается в простой строке Java, которая является compiled в опкоды
  • нет проверки типа
  • нет дженерики
  • нет лямбда
  • нет авто-(ООН)по боксу

также Javassist распознается медленнее, чем Cglib. Это в основном связано с его подходом к чтению файлов классов вместо чтения загруженных классов, таких как CGLIB. А то реализация трудно читать, чтобы быть справедливым ; если требуется чтобы внести изменения в код Javassist, есть много шансов что-то сломать.

Javassist также страдал от бездействия, их переход к github около 2013 кажется, оказалось полезным, поскольку он показывает регулярные коммиты и запросы на вытягивание из сообщества.

эти ограничения все еще стоят в версии 3.17.1. Версия была наткнулась на версию 3.20.0, но, похоже, Javassist все еще может иметь проблемы с Java 8 поддержка.

JiteScript

JiteScript действительно кажется новой частью красиво формирующейся DSL для ASM, это основано на последнем выпуске ASM (4.0). Код выглядит чистым.

но проект все еще находится в раннем возрасте, поэтому API / поведение может измениться, плюс документация ужасна. И обновления редкие, если не заброшенные.

Proxettajodd

это a довольно новый инструмент, но он предлагает намного лучше человека API. Он позволяет использовать различные типы прокси, такие как прокси подкласса (подход cglib) или переплетение или делегирование.

хотя, это довольно редко, никакой информации не существует, если он хорошо работает. Есть так много угловых случаев, чтобы иметь дело с при работе с байт-кодом.

AspectJaspectj

AspectJ является очень мощным инструментом для аспектно-ориентированное программирование (только). AspectJ манипулирует байтовым кодом для достижения своих целей, чтобы вы могли достичь своих целей с его помощью. Однако это требует манипуляций во время компиляции; spring предлагает плетение во время загрузки через агент начиная с версии 2.5, 4.1.x.

CGLIBcglib

слово о CGLIB, которое было обновлено с тех пор, как был задан этот вопрос спросил.

CGLIB довольно быстро, это одна из основных причин, почему он все еще вокруг, наряду с тем, что CGLIB работал почти лучше, чем любые альтернативы до сих пор (2014-2015).

вообще говоря, библиотеки, которые позволяют переписывать классы во время выполнения, должны избегать загрузки любых типов до перезаписи соответствующего класса. Поэтому они не могут использовать API отражения Java, который требует, чтобы любой тип, используемый в отражении, был загружен. Вместо этого они должны читать файлы классов через IO (который является прерывателем производительности). Это делает, например, Javassist или Proxetta значительно медленнее, чем Cglib, который просто читает методы через API отражения и переопределяет их.

однако CGLIB больше не находится в активной разработке. Были последние релизы, но эти изменения были замечены как незначительные многими, и большинство людей никогда не обновлялись до версии 3, так как CGLIB представил некоторые суровые баги в последних релизах то, что на самом деле не создавало уверенности. версия 3.1 исправлено много бед версии 3.0 (начиная с версии 4.0.3 Spring framework переупаковки версия 3.1).

кроме того, исходный код CGLIB имеет скорее плохое качество такие, что мы не видим новых разработчиков, присоединяющихся к проекту CGLIB. Для получения впечатления от активности CGLIB см. Их рассылки.

обратите внимание, что после предложение в списке рассылки guice, CGLIB теперь доступен на github чтобы сообщество могло лучше помочь проекту, он, похоже, работает (несколько коммитов и запросов на вытягивание, ci, обновленный maven), но большинство проблем все еще остаются.

в это время работают над версией 3.2.0, и они фокусируют усилия на Java 8, но до сих пор пользователи, которые хотят, чтобы поддержка java 8 должна использовать трюки во время сборки. Но прогресс очень медленный.

и CGLIB по-прежнему известно, что страдает от утечки памяти PermGen. Но другие проекты, возможно, не были испытаны в бою в течение стольких лет.

время компиляции, обработки аннотациианнотации-обработки

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

это началось с Java 5 это поставляется с отдельным инструментом командной строки для обработки аннотаций:apt, и начиная с Java 6 обработка аннотаций интегрируется в компилятор Java.

в какой-то момент Вы должны явно передавать процессор, теперь с ServiceLoader подход (просто добавьте этот файл META-INF/services/javax.annotation.processing.Processor к jar) компилятор может автоматически обнаружить процессор аннотаций.

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

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

вывод

на 2002 CGLIB определил новый стандарт для манипулировать байт-код с легкостью. Многие инструменты и методологии (CI, охват, TDD и т. д.) мы в наше время были недоступны или не созрели в то время. CGLIB удалось быть актуальным более десяти лет; это довольно приличное достижение. Это было быстро и с простым API в использовании, чем непосредственно манипулировать опкодами.

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

JVM изменился и будет меняться в последних и будущих версиях Java (7/8/9/10) (invokedynamic, методы по умолчанию, типы значений и т. д.). ASM регулярно обновлял свой API и внутренние устройства, чтобы следить за этими изменениями, но CGLIB и другие еще не использовали их.

в то время как обработка аннотаций получает тягу, она не так гибка, как генерация времени выполнения.

2015 года, Byte Buddy -в то время как довольно новый на сцене - предложение самый неотразимый продажа точки для генерации времени выполнения. Приличная скорость обновления, и автор имеет глубокое знание внутренних байт-кодов Java.

Javassist.

Если вам нужно сделать прокси, посмотри commons-proxy - он использует как CGLIB, так и Javassit.

Я предпочитаю raw ASM, который я считаю, используется cglib в любом случае. Это низкий уровень, но документация блестящий, и как только вы привыкнете к нему вы будете летать.

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

Я думаю, что это больше смысла использовать Javassist вместо cglib. Например, javasist отлично работает с подписанными банками в отличие от cglib. Кроме того, такие грандиозные, как Hibernate project решил прекратить использование cglib в пользу Javassist.

CGLIB был разработан и реализован более десяти лет назад в эпоху AOP и ORM. В настоящее время я не вижу причин использовать его, и я больше не поддерживаю эту библиотеку (за исключением исправлений ошибок для моих устаревших приложений ). На самом деле все случаи использования CGLIB, которые я когда-либо видел, являются анти-шаблонами в современном программировании. Должно быть тривиально реализовать ту же функциональность с помощью любого языка сценариев JVM, например groovy.