The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

未使用のBeanとそれを取り除く理由

Quarkusはビルド時重視のスタックです。つまり、アプリケーションの起動時間とメモリ使用量を改善するために、ビルド時に可能な限りのことをしようとします。しかし、既存のフレームワークやライブラリの多くがこの設計上の選択を考慮していないため、必ずしも簡単でわかりやすいものではありません。CDIはその一つです。

なぜわざわざ

従来のCDIコンテナは、アプリケーションのブートストラップ時にすべてのBeanを見つけようとします。各Beanに対して、メタデータオブジェクトが作成され、アプリケーションの寿命まで保持されます。これにより、ランタイムにある程度の動的性を持たせることができますが、メモリ消費やアプリケーションの起動時間に関しては最適ではありません。一方、Quarkusは、デフォルトでビルド時に 未使用の Bean、Interceptor、Decoratorをすべて検出して削除しようとします。その理由は簡単です。この最適化により、生成されるクラスの量と実行時に使用されるメタデータオブジェクトの数を最小限に抑え、メモリを節約することができます。

生成されたクラスについて。Beanの検出、検証、すべてのコンポーネントのワイヤリングは、すべてビルド時に実行されます。Quarkusでは、収集したメタデータをバイトコードに格納し、各Beanに対して1つ以上のクラスを生成します。いくつかの基本的なCDI API要件を満たすために、Beanは少なくとも対応する javax.enterprise.inject.spi.Bean の実装を持っています。それが通常のスコープ付きBeanである場合,クライアントプロキシクラスも生成されなければなりません。最後に,インターセプトされたBean及び装飾されたBeanは,さらにいくつかの内部構造を必要とします。

アプリケーションに、実際にはどこにも使われていない50個のBeanが含まれているとします。それらが通常のスコープ(例: @ApplicationScoped )を持ち、インターセプトされた場合(例: @Transactional でアノテーションされたメソッドを宣言する)、150以上のクラスが生成されることが予想されます。そして、これらのクラスは全く役に立たない。それでも、コンテナはこれらの50以上のBeanメタデータクラスをインスタンス化し、参照を保持する必要があります。言うまでもなく、ネイティブイメージを生成する際に、Beanクラスや参照されるクラスをデッドコード排除の対象とすることはできません。そこで、Quarkusでは、これらのクラスをすべて削除するアルゴリズムを実装しています。

実際に削除されるものは?

Quarkusはまず、依存関係ツリーのルートを形成する、いわゆる 削除不可能な Beanを特定します。削除不可能なBean:

  • オブザーバー・メソッドを宣言するか

  • @Named を通して指定された名前を持っているか

  • @io.quarkus.arc.Unremovable でアノテーションされているか

  • quarkus.arc.unremovable-types コンフィグ・プロパティによって除外されているか

  • Quarkusのエクステンションで識別されているか。

最後の点が最も重要であると思われます。なぜならば、これはアプリケーションのエントリーポイントが削除できないようにする方法だからです。例えば、RESTEasyエクステンションで識別されるJAX-RSリソースクラスが良い例です。もう1つの例は、 @Scheduled メソッドを宣言しているBeanで、Schedulerエクステンションによって識別されます。

_未使用の_Bean:

  • 削除不可能ではないこと

  • 依存関係ツリーのどの注入ポイントにも注入することが出来ないこと

  • 依存関係ツリーのどの注入ポイントにも注入可能なプロデューサーを宣言していないこと

  • javax.enterprise.inject.Instance または javax.inject.Provider の注入ポイントに注入することが出来ないこと

最後に、未使用のインターセプターとデコレーターは、どのBeanとも関連付けられていません。

開発モードを使用している場合(例: ./mvnw quarkus:dev を実行している場合)、どのBeanが削除されているかの詳細な情報をDev UIで見ることができます。

主な欠点

しかし、1つ問題があります。Quarkusは、 CDI.current() 静的メソッドを介して実行されるプログラムによるルックアップを検出できません。そのため、あるビーンの削除で誤検出エラーが発生する可能性があります。つまり、実際に使用されているにもかかわらずビーンが削除されてしまうのです。このような場合には、ログに大きな警告が表示されます。もちろん、ユーザーやエクステンションの作者には、このようなエラーをなくす方法がいくつかあります。ユーザーにとって最も簡単な方法は、特別なアノテーション @io.quarkus.arc.Unremovable を追加するか、 quarkus.arc.unremovable-types 設定プロパティを使用することです。最後に、 quarkus.arc.remove-unused-beans=false の設定プロパティでこの最適化を無効にすることも可能です。

まとめ

Quarkusは、使用されていないBeanを検出して削除し、サブアトミックアプリケーションへの道を支援します。また、何か問題が発生した場合には、この最適化の動作を設定できるオプションが用意されています。