code

cglib에 대한 대안이 있습니까?

codestyles 2020. 12. 29. 07:07
반응형

cglib에 대한 대안이 있습니까?


호기심에서 cglib 외에 런타임 Java 코드 생성을위한 (안정적인) 오픈 소스 프로젝트가 있습니까? 그리고 왜 사용해야합니까?


ASM

CGLIB 및 거의 모든 다른 라이브러리는 자체적으로 매우 낮은 수준에서 작동하는 ASM 위에 구축됩니다. 이것은 바이트 코드와 JVMS 를 제대로 사용하기 위해 이해해야하는 대부분의 사람들에게 보여줄 것입니다. 그러나 ASM을 마스터하는 것은 확실히 매우 흥미 롭습니다. 그러나 훌륭한 ASM 4 가이드 가 있지만 API의 일부에서 javadoc 문서가 존재한다면 매우 간결 할 수 있지만 개선되고 있습니다. 새로운 기능을 지원하기 위해 JVM 버전을 밀접하게 따릅니다.

그러나 모든 권한이 필요한 경우 ASM을 선택하는 것이 좋습니다.

이 프로젝트는 정기적으로 업데이트됩니다. 이 편집 당시 버전 5.0.4는 2015 년 5 월 15 일에 출시되었습니다.

바이트 버디

Byte Buddy는 다소 새로운 라이브러리이지만 CGLIB 또는 Javassist가 제공하는 모든 기능 등을 제공합니다. Byte Buddy는 바이트 코드 수준까지 완전히 사용자 정의 할 수 있으며 매우 읽기 쉬운 코드를 허용하는 표현적인 도메인 특정 언어와 함께 제공됩니다.

  • 기본 메소드와 관련된 일부 opcode의 Java 8 의미 변경을 포함하여 모든 JVM 바이트 코드 버전을 지원합니다.
  • ByteBuddy는 다른 라이브러리의 단점을 겪지 않는 것 같습니다.
  • 고도로 구성 가능
  • 매우 빠름 ( 벤치 마크 코드 )
  • 안전한 유창한 API 입력
  • 안전한 콜백 입력

    Javassist 조언 또는 사용자 정의 계측 코드는 일반 코드를 기반으로 String하므로이 코드 내에서 유형 검사 및 디버깅이 불가능한 반면, ByteBuddy는 순수한 Java로 작성할 수 있으므로 유형 검사를 시행하고 디버깅을 허용합니다.

  • 주석 기반 (유연)

    사용자 콜백은 콜백에서 원하는 매개 변수를 수신 할 수 있도록 주석으로 구성 할 수 있습니다.

  • 에이전트로 사용 가능

    멋진 에이전트 빌더를 사용하면 ByteBuddy를 순수 에이전트 또는 부착 에이전트로 사용할 수 있습니다. 그것은 다른 종류를 허용합니다

  • 매우 잘 문서화 됨
  • 많은 예
  • 깨끗한 코드, ~ 94 % 테스트 범위
  • Android DEX 지원

주된 단점은 API가 초보자에게는 다소 장황하지만 프록시 생성 DSL 모양의 옵트 인 API로 설계되었다는 것입니다. 마법이나 의심스러운 기본값이 없습니다. 바이트 코드를 조작 할 때 아마도 가장 안전하고 합리적인 선택 일 것입니다. 또한 여러 예제와 큰 자습서를 사용하면 실제 문제가 아닙니다.

2015 년 10 월이 프로젝트는 Oracle Duke의 선택 상을 받았습니다 . 이 시점에서 그것은 단지 1.0.0 마일스톤에 도달했습니다. 이것은 상당한 성과입니다.

참고 대체하고 바이트 버디로 CGLIB를 버전 2.1.0에서.

자바

Javassist의 javadoc은 CGLIB보다 훨씬 낫습니다. 클래스 엔지니어링 API는 괜찮지 만 Javassist도 완벽하지 않습니다. 특히 ProxyFactoryCGLIB와 동등한 것 Enhancer역시 몇 가지 단점을 가지고 있습니다.

  • Bridge 메서드는 완전히 지원되지 않습니다 (예 : 공변 반환 유형에 대해 생성 된 메서드).
  • ClassloaderProvider 대신 정적 필드 인 경우 동일한 클래스 로더 내의 모든 인스턴스에 적용됩니다.
  • 사용자 지정 이름 지정을 환영 할 수 있습니다 (서명 된 jar 확인 포함)
  • 확장 점이없고 관심있는 거의 모든 방법이 비공개이므로 일부 동작을 변경하려는 경우 번거 롭습니다.
  • Javassist는 클래스의 주석 속성에 대한 지원을 제공하지만 ProxyFactory.

측면 지향적 측면에서 프록시에 코드를 삽입 할 수 있지만 Javassist의이 접근 방식은 제한적이며 오류가 발생하기 쉽습니다.

  • aspect 코드는 opcode 컴파일 되는 일반 Java 문자열로 작성됩니다.
  • 유형 검사 없음
  • 제네릭 없음
  • 람다 없음
  • 자동 (un) boxing 없음

또한 Javassist는 Cglib보다 느린 것으로 인식됩니다. 이것은 주로 CGLIB처럼로드 된 클래스를 읽는 대신 클래스 파일을 읽는 접근 방식 때문입니다. 그리고 구현 자체는 공정하기 위해 읽기 어렵습니다. Javassist 코드를 변경해야하는 경우 무언가를 깨뜨릴 가능성이 많습니다.

Javassist도 비활성 상태로 고통 받았으며 2013 년경 github 로의 이동 은 커뮤니티의 정기적 인 커밋과 풀 요청을 보여 주므로 유용한 것으로 입증되었습니다.

이러한 제한은 버전 3.17.1에 여전히 존재합니다. 버전은 3.20.0 버전으로 올라갔지 만 Javassist는 여전히 Java 8 지원에 문제가있을 수 있습니다.

JiteScript

JiteScript는 최신 ASM 릴리스 (4.0)를 기반으로하는 ASM 용 DSL을 멋지게 구성하는 새로운 조각처럼 보입니다. 코드가 깨끗해 보입니다.

그러나이 프로젝트는 아직 초기 단계이므로 API / 동작이 변경 될 수 있으며 문서도 무시 무시합니다. 포기하지 않으면 거의 업데이트되지 않습니다.

프록

이것은 다소 새로운 도구이지만 최고의 인간 API를 제공합니다 . 서브 클래스 프록시 (cglib 접근 방식) 또는 위빙 또는 위임과 같은 다양한 유형의 프록시를 허용합니다.

이것은 드물지만 잘 작동하면 정보가 존재하지 않습니다. 바이트 코드를 다룰 때 다루어야 할 코너 케이스가 너무 많습니다.

AspectJ

AspectJ는 측면 지향 프로그래밍을 위한 매우 강력한 도구입니다 (전용). AspectJ는 목표를 달성 할 수 있도록 바이트 코드를 조작합니다. 그러나이를 위해서는 컴파일 타임에 조작이 필요합니다. 버전 2.5 , 4.1.x 이후 에이전트를 통해로드 시간에 스프링 오퍼 위빙 .

CGLIB

그 질문 이후 업데이트 된 CGLIB에 대한 한마디.

CGLIB는 매우 빠르며, CGLIB가 지금까지 (2014-2015) 어떤 대안보다 거의 잘 작동했다는 사실과 함께 여전히 주변에있는 주된 이유 중 하나입니다.

Generally speaking libraries that allow the rewriting of classes at run time have to avoid loading any types before the corresponding class is rewritten. Therefore, they cannot make use of the Java reflection API which requires that any type used in reflection is loaded. Instead, they have to read the class files via IO (which is a performance-breaker). This makes for example Javassist or Proxetta significantly slower than Cglib which simply reads the methods via the reflection API and overrides them.

However, CGLIB is no longer under active development. There were recent releases but those changes were seen as insignificant by many and most people did never update to version 3 since CGLIB introduced some severe bugs in the last releases what did not really build up confidence. Version 3.1 fixed a lot of the woes of version 3.0 (since version 4.0.3 Spring framework repackages version 3.1).

Also, the CGLIB source code is of rather poor quality such that we do not see new developers joining the CGLIB project. For an impression of CGLIB's activeness, see their mailing list.

Note that following a proposition on the guice mailing list, CGLIB is now available on github to enable the community to better help the project, it appears to be working (multiple commits and pull requests, ci, updated maven), yet most concerns still remain.

At this time there are working on version 3.2.0, and they are focusing effort on Java 8, but so far users that want that java 8 support have to use tricks at build time. But progress is very slow.

And CGLIB is still known to be plagued for PermGen memory leak. But other projects may not have been battle tested for so many years.

Compile time annotation Processing

This one is not runtime of course, but is an important part of the ecosystem, and most code generation usage don't need runtime creation.

This started with Java 5 that came with the separate command line tool to process annotations : apt, and starting from Java 6 annotation processing is integrated into the Java compiler.

At some time you were required to explicitly pass the processor, now with the ServiceLoader approach (just add this file META-INF/services/javax.annotation.processing.Processor to the jar) the compiler can detect automatically the annotation processor.

This approach at code generation has drawbacks too it require a lot of work and understanding of the Java language not bytecode. This API is a bit cumbersome, and as one is plugin in the compiler one must take extreme care to make this code the most resilient and user friendly error message.

The biggest advantage here is that it avoids another dependency at runtime, you may avoid permgen memory leak. And one has full control on the generated code.

Conclusion

In 2002 CGLIB defined a new standard to manipulate bytecode with ease. Many tools and methodology (CI, coverage, TDD, etc.) we have nowadays were not available or not mature at that time. CGLIB managed to be relevant for more than a decade ; that's a pretty decent achievement. It was fast and with an easy API to use than manipulating opcodes directly.

It defined new standard regarding code generation but nowadays it isn't anymore because environment and requirements have changed, so have the standards and goals.

The JVM changed and will change in recent and future Java (7/8/9/10) versions (invokedynamic, default methods, value types, etc). ASM upgraded his API and internals regularly to follow these changes but CGLIB and others have yet to use them.

While annotation processing is getting traction, it is not as flexible as runtime generation.

As of 2015, Byte Buddywhile rather new on the scene — offer the most compelling selling points for runtime generation. A decent update rate, and the author has an intimate knowledge of the Java byte code internals.


Javassist.

If you need to make proxies, take a look at commons-proxy - it uses both CGLIB and Javassit.


I prefer raw ASM, which I believe is used by cglib anyway. It's low level, but the documentation is brilliant, and once you get used to it you'll be flying.

To answer your second question, you should use code generation when your reflection and dynamic proxies are beginning to feel a bit cobbled together and you need a rock solid solution. In the past I've even added a code generation step into the build process in Eclipse, effectively giving me compile time reporting of anything and everything.


I think it's more sense to use Javassist instead of cglib. E.g. javasist perfectly works with signed jars unlike cglib. Besides, such grand as Hibernate project decided to stop using cglib in favor of Javassist.


CGLIB는 AOP 및 ORM 시대에 10 년 이상 전에 설계되고 구현되었습니다. 현재 나는 그것을 사용할 이유가 없으며 더 이상이 라이브러리를 유지하지 않습니다 (레거시 애플리케이션의 버그 수정 제외). 실제로 내가 본 모든 CGLIB 사용 사례는 현대 프로그래밍에서 안티 패턴입니다. JVM 스크립팅 언어 (예 : groovy)를 통해 동일한 기능을 구현하는 것은 간단해야합니다.

참조 URL : https://stackoverflow.com/questions/2261947/are-there-alternatives-to-cglib

반응형