質問

単なる好奇心ですが、cglib 以外にランタイム Java コード生成用の (安定した) オープンソース プロジェクトはありますか?なぜそれらを使用する必要があるのでしょうか?

役に立ちましたか?

解決

ASM

CGLIB および他のほとんどすべてのライブラリは、ASM 自体が非常に低レベルで動作する ASM 上に構築されています。バイトコードと少しの JVMS 正しく使うために。しかし、ASM をマスターすることは間違いなく非常に興味深いものです。ただし、 素晴らしい ASM 4 ガイド, 、API の一部では、Javadoc ドキュメントが存在する場合は非常に簡潔になりますが、改善されています。JVM バージョンに厳密に従って新機能をサポートします。

ただし、完全な制御が必要な場合は、ASM が最適な武器です。

このプロジェクトは定期的に更新されます。この編集時点では、バージョン 5.0.4 は 2015 年 5 月 15 日にリリースされました。

バイトバディ

Byte Buddy はかなり新しいライブラリですが、CGLIB や Javassist が提供する機能などを提供します。Byte Buddy はバイト コード レベルまで完全にカスタマイズでき、非常に読みやすいコードを可能にする表現力豊かなドメイン固有言語が付属しています。

  • デフォルトメソッドに関する一部のオペコードの Java 8 セマンティック変更を含む、すべての JVM バイトコード バージョンをサポートします。
  • ByteBuddy は他のライブラリのような欠点を抱えていないようです
  • 高度に構成可能
  • かなり速いです (基準 コード)
  • タイプセーフで滑らかな API
  • タイプセーフなコールバック

    Javassist のアドバイスまたはカスタム インストルメンテーション コードは、プレーンなコードに基づいています。 String したがって、このコード内では型チェックとデバッグは不可能ですが、ByteBuddy では純粋な Java でこれらを作成できるため、型チェックが強制され、デバッグが可能になります。

  • 注釈主導型 (柔軟)

    ユーザー コールバックは、コールバックで必要なパラメータを受け取ることを可能にするアノテーションを使用して構成できます。

  • 代理店として利用可能

    気の利いたエージェント ビルダーを使用すると、ByteBuddy を純粋なエージェントまたは接続エージェントとして使用できます。さまざまな種類を許可します

  • 非常によく文書化されています
  • たくさんの例
  • クリーンなコード、最大 94% のテスト カバレッジ
  • Android DEX のサポート

おそらく主な欠点は、API が初心者にとっては少し冗長ですが、プロキシ生成 DSL の形をしたオプトイン API として設計されていることです。魔法や疑わしいデフォルトはありません。バイト コードを操作する場合、これがおそらく最も安全で合理的​​な選択です。また、複数の例と大きなチュートリアルがあるため、これは実際の問題ではありません。

2015 年 10 月に、このプロジェクトは オラクル・デューク・チョイス・アワード. 。この時点では、ちょうど到達しました 1.0.0 マイルストーン, 、これはかなりの成果です。

ご了承ください 置き換えられました CGLIB byte Buddy バージョン2.1.0では。

ジャバシスト

Javassist の javadoc は CGLIB の javadoc よりもはるかに優れています。クラスエンジニアリング API は問題ありませんが、Javassist も完璧ではありません。特に、 ProxyFactory これは CGLIB と同等です Enhancer いくつか挙げると、いくつかの欠点もあります。

  • Bridge メソッドは完全にはサポートされていません (つまり、共変戻り値の型に対して生成されるメソッド)
  • ClassloaderProvider 代わりに静的フィールドである場合、同じクラスローダー内のすべてのインスタンスに適用されます
  • カスタムの名前付けは歓迎されたかもしれません (署名された jar をチェックする)
  • 拡張ポイントがなく、対象となるメソッドのほぼすべてがプライベートであるため、動作を変更したい場合に面倒です。
  • Javassist はクラス内の注釈属性のサポートを提供しますが、それらはクラス内ではサポートされません。 ProxyFactory.

アスペクト指向の側では、プロキシにコードを挿入できますが、Javassist でのこのアプローチは制限されており、少しエラーが発生しやすくなります。

  • アスペクト コードはプレーンな Java 文字列で記述されます。 編集済み オペコード内
  • 型チェックなし
  • ジェネリック医薬品はありません
  • ラムダがありません
  • 自動(解除)ボックス化なし

また、Javassist は Cglib よりも遅いと認識されています。これは主に、CGLIB のようにロードされたクラスを読み取るのではなく、クラス ファイルを読み取るアプローチによるものです。そしてその 実装 それ自体は公平を期すために読むのが難しいです。Javassist コードに変更を加える必要がある場合、何かが壊れる可能性がたくさんあります。

Javassist も活動の停止に悩まされました。 2013年頃のgithub コミュニティからの定期的なコミットとプルリクエストが表示されるため、有用であることが証明されているようです。

これらの制限はバージョン 3.17.1 にもまだ残っています。バージョンはバージョン 3.20.0 に上がりましたが、Javassist には Java 8 サポートに関してまだ問題があるようです。

JiteScript

JiteScript は、ASM 用の DSL をうまく構成する新しい部分のように見えますが、これは最新の ASM リリース (4.0) に基づいています。コードがきれいに見えます。

しかし プロジェクトはまだ初期段階にあるため、API や動作が変更される可能性があり、さらにドキュメントはひどいものです。そして、放棄されていないとしても、更新はほとんどありません。

プロクセッタ

これはかなり新しいツールですが、これまでで最高の機能を提供します 人間 API。これにより、サブクラス プロキシ (cglib アプローチ) やウィービング、委任などのさまざまなタイプのプロキシが可能になります。

ただし、これはかなりまれで、うまく動作するかどうかの情報はありません。バイトコードを扱う際には、対処すべき特殊なケースが非常に多くあります。

アスペクトJ

AspectJ は非常に強力なツールです。 アスペクト指向プログラミング (のみ)。AspectJ はバイト コードを操作してその目標を達成するため、ユーザーはそれを使用して目標を達成できる可能性があります。ただし、これにはコンパイル時の操作が必要です。バージョン以降、ロード時にエージェントを介してスプリングオファーを織り込む 2.5, 4.1.x.

CGLIB

CGLIB について、その質問がされてから更新された一言。

CGLIB は非常に高速であり、CGLIB が現在 (2014 年から 2015 年) までのどの代替手段よりもほぼうまく機能したという事実とともに、CGLIB がまだ存在している主な理由の 1 つです。

一般に、実行時にクラスの書き換えを許可するライブラリでは、対応するクラスが書き換えられる前に型をロードすることを回避する必要があります。したがって、リフレクションで使用される型をロードする必要がある Java リフレクション API を利用することはできません。代わりに、IO 経由でクラス ファイルを読み取る必要があります (これはパフォーマンスを低下させます)。これにより、たとえば Javassist や Proxetta は、単にリフレクション API 経由でメソッドを読み取ってオーバーライドする Cglib よりも大幅に遅くなります。

ただし、CGLIB は現在は積極的に開発されていません。最近のリリースもありましたが、それらの変更は多くの人にとって重要ではないと見なされ、CGLIB がいくつかの機能を導入して以来、ほとんどの人はバージョン 3 に更新しませんでした。 深刻なバグ 前回のリリースでは、実際には自信を築くことができませんでした。 バージョン 3.1 では、バージョン 3.0 の問題点の多くが修正されました (バージョン 4.0.3 の Spring Framework の再パッケージ以降) バージョン3.1).

また、CGLIB ソース コードは、 質の悪い そのため、CGLIB プロジェクトに新しい開発者が参加することはありません。CGLIB の活発な印象については、彼らの記事を参照してください。 メーリングリスト.

次のことに注意してください。 Guice メーリング リストでの提案, 、CGLIB は現在、以下で利用可能です。 ギットハブ コミュニティがプロジェクトをより良く支援できるようにするため、プロジェクトは機能しているように見えますが (複数のコミットとプル リクエスト、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 は 10 年以上にわたって関連性を保っていました。それはかなりまともな成果です。オペコードを直接操作するよりも高速で、API が使いやすかったです。

コード生成に関する新しい標準を定義しましたが、環境と要件が変化し、標準と目標も変化したため、現在では定義されていません。

JVM は変更されており、最近および将来の Java (7/8/9/10) バージョン (invokedynamic、デフォルト メソッド、値の型など) で変更される予定です。ASM はこれらの変更に追従するために API と内部を定期的にアップグレードしましたが、CGLIB やその他の企業はまだそれらを使用していません。

アノテーション処理は注目を集めていますが、ランタイム生成ほど柔軟ではありません。

2015年現在、 バイトバディシーンではかなり新しいですが — 最も魅力的なものを提供する 販売 ランタイム生成のポイント。まともな更新速度であり、作成者は Java バイト コードの内部についての深い知識を持っています。

他のヒント

Javassistののます。

あなたがプロキシを作成する必要がある場合は、コモンズ・プロキシのを見てみましょう - それは、両方のCGLIBを使用していますそしてJavassitます。

私はとにかくCGLIBによって使用されていると信じていた生 ASM に、好みます。それは低レベルですが、ドキュメントはの輝かしいの、あなたがそれに慣れると、あなたが飛ぶことがあります。

あなたの反射や動的プロキシビットが一緒に石畳とあなたは岩の固体ソリューションを必要と感じ始めているときに2つ目の質問に答えるために、あなたはコード生成を使用する必要があります。過去には私も効果的に、私は何も、すべての時間の報告をコンパイル与え、Eclipseのビルドプロセスにコード生成ステップを追加しました。

私はそれが代わりに Javassistのに使用するより多くの意味だと思いますCGLIB。例えば。 javasistは完全にCGLIBとは異なり、署名のjarファイルで動作します。また、Hibernateのプロジェクトのなどの壮大はJavassistのでの賛成でCGLIBの使用を停止することを決定します。

CGLIBは、AOPとORMの時代に十年以上前に設計され、実装されました。 現在、私はそれを使用する一切の理由を見ていないし、私は(私のレガシーアプリケーションのためのバグ修正を除く)もうこのライブラリを維持していません。 実は、すべて私が今まで見たを持ってCGLIBの使用例は、現代のプログラミングにおける抗パターンです。 任意のJVMスクリプト言語などを経由して、同じ機能を実装するために些細でなければなりませんグルーヴィーます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top