Upgrade to Pro — share decks privately, control downloads, hide ads and more …

CDIの誤解しがちな仕様とその対処TIPS

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for futokiyo futokiyo
February 24, 2026

 CDIの誤解しがちな仕様とその対処TIPS

日本Jakarta EE & MicroProfile ユーザーグループ 第1回勉強会 CDIの誤解しがちな仕様とその対処TIPSスライド
TIPS【1】WELD-000075 DefinitionException
TIPS【2】同クラス内のメソッドを呼び出すとインターセプターが掛からない
TIPS【3】Javaのクラスが多過ぎるとear/warアプリが起動しなくなる
TIPS【4】 CDI.current().select().get()で取得したDependentスコープのインスタンスがメモリ解放されない

Avatar for futokiyo

futokiyo

February 24, 2026
Tweet

Other Decks in Programming

Transcript

  1. 日本Jakarta EE & MicroProfile ユーザーグループ 第1回勉強会 CDIの誤解しがちな仕様 とその対処TIPS アクセンチュア株式会社 テクノロジー

    コンサルティング本部 ITソリューション FUTOSHI YOSHIZAKI 2026/02/24 © 2026 Accenture All Rights Reserved
  2. © 2026 Accenture All Rights Reserved 2 このセッションについて  足掛け6年に渡り、Java

    EE 7のCDIを実案件で使用しておりました。アサイン当初は、 CDIに関する書籍を読んで臨みましたが、実際にやってみると、書籍では書かれていな いような出来事や理解の浅かった事がいくつかありました。  当セッションでは、私が実案件の中でつまづいた実例を元に、CDIを扱う上で、書籍等 ではあまり強調されていない知見をお話します。  免責事項  当セッションの内容およびデモアプリのソースコードは、私自身の見解を反映しており、必ずしも雇用主の見解を代表す るものではありません。
  3. © 2026 Accenture All Rights Reserved 必要な前提知識 このセッションを理解するには、以下の前提知識が必要です。 Jakarta(Java) Contexts

    and Dependency Injection Dependency Inject(依存性の注入) AOP(アスペクト指向プログラミング) JavaのGCに関する基礎知識
  4. © 2026 Accenture All Rights Reserved 前提知識を学べる資料 Java EE 7徹底入門

    - 翔泳社 https://www.shoeisha.co.jp/book/detail/9784798140926 パーフェクト Java EE - 技術評論社 https://gihyo.jp/book/2016/978-4-7741-8316-9 Jakarta Contexts and Dependency Injection 規格文書 - https://jakarta.ee/specifications/cdi/
  5. © 2026 Accenture All Rights Reserved 6 自己紹介 略歴 2000年に非鉄金属メーカーのユーザー系SIerに新卒入社、主にグループ会社の社内シ

    ステム構築に携わる。 2003年に株式会社ソピアにジョインし、2012年に現在の会社に転 籍。 多業種にわたり様々な規模のエンタープライズ向けJavaアプリケーションやアーキテクチャの 設計・開発に⾧年従事。 近年は、JCLやCOBOL等のメインフレーム資源を、Javaアプリケーションで稼働できるアプ リ基盤の設計・開発にいそしむ。 Futoshi Yoshizaki Manager Technology Accenture Japan [email protected]
  6. © 2026 Accenture All Rights Reserved CDIとは何か Java EE 6から導入されたJava

    EE版のDI仕様。 Contexts and Dependency Injectionの略 Jakarta EE 9以降の正式名称は、「Jakarta Contexts and Dependency Injection」 Dependency:「再利用されうるオブジェクトや設定情報」。 Injection(注入):「外部代入」 ※意訳 CDIにより提供される主要な機能は次の5つ。 Dependency Injection(依存性の注入) 1 スコープによるBeanインスタンスのライフサイクル管理 2 アスペクト指向プログラミング(AOP/インターセプタ、デコレータ) 3 イベント通知(Observerパターンの実装) 4 EL式との連携 5 • クラスを再利用しやすくなる。 • コードを修正しやすくなる。 • Jakarta EE APサーバーの恩恵(JTAやトランザクションマネージャなど)を享受しやすくなる。 CDIにより得られるメリット
  7. © 2026 Accenture All Rights Reserved CDIを採用する積極的な理由 • 商用Jakarta EE

    APサーバー・ベンダーとサブスクリプション契約などを結んでい れば、障害が発生した場合に、調査の依頼ができる。 • 実案件でCDI実装の不具合が判明し、改修に至ったケースは実際にあった。 • 上記契約を結んでいれば、仕様や実装に関する不明点などがある際に、サポート窓口に問い合わせ が可能。 • ただし、仕様に対する機能追加などのエンハンスメント・リクエストはなかなか通りにくいことに注意。 • Jakarta EEの実装クラスは、Jakarta EE APサーバー内にパッケージ製品とし て提供済みであり、その分、warのサイズを節約できる。 • 知名度や普及度の高いフレームワークをメタフレームワークにすることで人材の流 動性を高め、開発要員や保守要員を確保しやすくなる。
  8. © 2026 Accenture All Rights Reserved デモの概要 実案件で使用していたJEEアプリのランタイムはJavaEE7ということなどもあり、ソースコードは公開不可 そこで、当セッションでできるだけ再現性のあるソースコードを提示するために、4つのTIPSごとにデモアプリを 実装。

    開発ランタイムの仕様は次の通り。 • Java SE 17 • Jakarta EE 10 • Jakarta CDI 4.0.1 • JBoss EAP 8.0.x これから紹介するTIPSの事象を再現するためのソースコードは次のパスで公開している ① TIPS01 https://github.com/jjugnsjeecditips202602/febtips01 ② TIPS02 https://github.com/jjugnsjeecditips202602/febtips02 ③ TIPS03 https://github.com/jjugnsjeecditips202602/febtips03 ④ TIPS04 https://github.com/jjugnsjeecditips202602/febtips04 ビルド・デプロイ手順、動作確認方法は各README.mdを参照の事。 TODO管理から学習作業を行うという疑似業務を行うという想定して、サンプルアプリを実装している。
  9. © 2026 Accenture All Rights Reserved TIPS【1】WELD-000075 DefinitionException トラブル事象 次のようなBeanを作成すると、コンパイルエラーは起きないが、

    https://github.com/jjugnsjeecditips202602/febtips01/blob/main/src/main/java/io/github/futokiyo/febtips01/service/TodoService.java Webアプリケーションのデプロイ時に、 「WELD-000075: Normal scoped managed bean implementation class has a public field」 というエラー文言のDefinitionExceptionが発生し、デプロイが失敗する。 ※「WELDって何?」 APPENDIXの豆知識を参照
  10. © 2026 Accenture All Rights Reserved TIPS【1】WELD-000075 DefinitionException 解消方法 JBoss.orgのCDI仕様文書「3.1.

    Managed beans」では次のように説明されている。 https://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#managed_beans If a managed bean has a non-static public field, it must have scope @Dependent. If a managed bean with a non-static public field declares any scope other than @Dependent, the container automatically detects the problem and treats it as a definition error. 意訳: 管理対象ビーンがpublicのインスタンスフィールドを持つ場合、@Dependentスコープでなければならな い。 @Dependentスコープ以外のスコープだと、コンテナが自動的に問題を検出し、定義エラーとして扱う。 解消方法としては、次の2つ ①ビーンスコープを@Dependentにする。 ②またはアクセス修飾子をpublicからそれ以外のもの(protectedなど)に変更する。 後述するが、安易にDependentスコープに変えないことを推奨。むしろ、アクセス修飾子をpublic以外 に変更して問題が無いかを検討するべき。
  11. © 2026 Accenture All Rights Reserved TIPS【1】WELD-000075 DefinitionException 原因 WELD-000075

    DefinitionExceptionが発生する条件 1). CDIビーンのスコープが@Dependent以外のもの(≒ノーマルスコープのビーン) 2). publicなインスタンスフィールドが定義されている。 このような問題が起きる根本的な原因を理解するには、 ・クライアントプロキシ(Weld Proxy) ・ノーマルスコープと疑似スコープ という二つの論点を理解する必要がある。
  12. © 2026 Accenture All Rights Reserved TIPS【1】のデモ 実際に、JBoss EAPにWebアプリケーションをデプロイして、 WELD-000075DefinitionException

    を起こしてみる。 jjugnsjeecditips202602/febtips01: WELD-000075 DefinitionException を再現 続いて、TodoServiceクラスのlearnフィールドの修飾子をpublicからprivateに変えて、デプロイ できることを確認する。 どうしてこの修正だけで、デプロイが通るようになるのか。 これを推察するには、コンテキストとノーマルスコープとクライアントプロキシの理解が必要。
  13. © 2026 Accenture All Rights Reserved クライアントプロキシ 詳細な解説は技術評論社 「パーフェクト Java

    EE」 P63~P74より、一部、引用させていただく。 コンテキストとは、各CDI管理Beanが持つスコープ定義に応じて、あるスレッドが置かれた状況を示す。 CDIは、各スコープが意図するコンテキストを考慮して、インスタンスの状態管理を行っている。 CDIでは直接CDI管理Beanのインスタンスをインジェクションせず、「クライアントプロキシ」をインジェクトし、 下の図に示すようにプロキシ経由でCDI管理Beanを操作させることで、Bean間の参照の依存を分離して いる。 @ApplicationScoped @ApplicationScoped @RequestScoped HelloTips01 • learn • todoService TodoService • learn learnのクライアントプロキシ learnのクライアントプロキシ todoServiceのクライアントプロキシ Learn • msg : Would_you_learn_CDI_? Learn • msg : CDIisWeld Httpリクエスト AのLearnインスタンス Httpリクエスト BのLearnインスタンス HTTPリクエストごとに、クライアントプロキシが参照するLearnインスタンスが 差し替えられ、サーブレットからは常に正しいインスタンスが参照可能。 クライアントプロキシの仕組みにより、異なるライフサイクルを持つインスタンスを 独立させている。 Weldにおけるクライアントプロキシ実装のことをWeld Proxyという。
  14. © 2026 Accenture All Rights Reserved ノーマルスコープと疑似スコープの違い ノーマルスコープ •前述の通り、コンテキストとクライアントプロキシによってライフサイクルが行われる通常 のスコープ

    •ノーマルスコープのBean間では、プロキシ経由でアクセスする仕組みにより、循環参 照が許容されている。 疑似スコープ •厳密にはスコープではなく、疑似スコープ定義のCDI管理Beanはクライアントプロ キシを経由せずにアクセスされる。 •疑似スコープのBeanによる循環参照はできない。
  15. © 2026 Accenture All Rights Reserved CDI規格として策定済みのスコープ • アプリケーションのデプロイからアンデプロイされるまで •

    ear/warのアプリケーション内で、アプリケーションスコープのインスタンスは共有される • 疑似スコープ。ライフサイクルはインジェクト先のクラスに依存する • bean-discovery-mode:allなどによるBean登録の際、スコープ定義無しのBeanはデフォルトでDependentと判断される • TIPS04で後述するが、動的取得すると、アプリケーションの責務で廃棄の必要性が発生する • 疑似スコープ。アプリケーション中で1つだけインスタンスが生成される • HTTPリクエストからレスポンスまでの間 • サーブレットフィルタ、ServletRequestListener, AsyncListenerの実行中を含む • JAX-RSによるWebサービスの受付から応答までの間 • サーブレットのservice()実行時から、セッションタイムアウト、またはHttpSession.invalidate()によりセッションが破棄されるまで • HTTPセッション間でセッションスコープのインスタンスは共有される • HttpSessionListener, ServletRequestListener, AsyncListenerの実行中を含む インスタンスの生存期間 • リクエストスコープ以上、セッションスコープ未満で任意の⾧さが指定できる • Conversation.begin()からConversation.end()の実行までの間 @ApplicationScoped @Dependent @Singleton @RequestScoped @SessionScoped スコープ @ConversationScoped 1 3 4 5 2 6 技術評論社 「パーフェクト Java EE」 P67 表3.2より引用
  16. © 2026 Accenture All Rights Reserved TIPS【1】WELD-000075 DefinitionException 根本的な理由 ノーマルスコープのBeanにpublicフィールドを定義すると、クライアントプロキシのフィールドを直接更新

    しても、CDI管理Beanインスタンスのフィールドに反映されない。このような誤った使い方を防止するた めだと思われる。 learnのクライアントプロキシ Learn •msg : null インジェクション先のインスタンスのメソッド内で、 learn.msg = “aaa”; という代入式を実行しても、 クライアントプロキシの参照先のlearn.msgには反映されない ちなみに、protectedフィールドとpackage privateフィールドを定義しても、デプロイできる。 ただ、カプセル化すれば、このようなことを考える必要はない。 WELD-000075 DefinitionExceptionが発生した際は、スコープをDependentにする前に、 本当にpublicフィールドが必要なのかを検討することが望ましい。
  17. © 2026 Accenture All Rights Reserved TIPS【2】同クラス内のメソッドを呼び出すとインターセプターが掛からない 事象 同じクラスのメソッドを呼ぶような処理がある場合、呼び出し元メソッドと呼び出し先メソッドにAOPのア ノテーションを宣言しても、呼び出し先メソッドのインターセプターが実行されない。

    具体例 LoggingInterceptor メソッドの開始のログを出 力する Logging (アノテーション) (1)インターセプターとアノ テーションを用意 Learn メソッド prepare: 学習の準備をする メソッド study: 勉強をする処理 当処理で、同じクラス内の preprareを呼び出す。 @Logging @Logging TodoService • learn メソッド doLearn: learn.study();を実行 (2)同クラス内のメソッドを呼ぶよ うなクラスを用意 具体的にはstudy()メソッド内で prepare()メソッドを 呼び出す。それぞれに@Loggingを 宣言 (3)インジェクション先の TodoServiceインスタンス内のメソッ ドで、learn.study()を呼び出す。 Learn.study()の 開始ログは出力さ れるが、 learn.prepare() の開始ログが出力 されない。
  18. © 2026 Accenture All Rights Reserved TIPS【2】同クラス内のメソッドを呼び出すとインターセプターが掛からない 原因 インターセプターのインスタンスは、プロキシのメソッドにWeaveされているから。 実体のLearnインスタンス#study()内でprepare()をコールすると、プロキシのprepareを経由しないため、

    prepare()の開始終了ログは出力されない。 TodoService • learn learnのプロキシ メソッド study イ ン タ セ プ タ ー メソッド prepare イ ン タ セ プ タ ー Learn メソッド prepare: メソッド study: this.prepare(); @Logging @Logging learn.study() ① ② ③ ④ ⑤ 順を追って説明すると、次の通り ①TodoServiceインスタンス内で、learnのプロキ シのstudy()メソッドを実行する。 ②プロキシに織り込まれたLoggingインターセプ ターの開始ログが出力される。 ③CDI管理Beanのlearn.study()が実行され、 ④studyメソッド内でprepare()メソッドが呼ばれ る。 ⑤study()メソッドの処理が終了する。 TodoServiceでlearn(プロキシ)のprepare()を呼ぶと、 Loggingインターセプターによるprepareメソッドの開始ログは出力される。
  19. © 2026 Accenture All Rights Reserved TIPS【2】のようなトラブルを防ぐには AOPのインターセプターのアーキテクチャー原理を正しく理解したうえで、要件定義や設計を行う。 付け加えると、Spring Frameworkでもこのような問題は発生する。

    気を付けるべきは、「アノテーションをつけただけで、インターセプターが動くようになる」と思わないこと! TIPS【2】のような問題が発生したときに、解決策はないのか。 実はある。但し、推奨ではないため、当発表では控えさせていただく。 (ヒントは、後述のTIPS【4】)
  20. © 2026 Accenture All Rights Reserved TIPS【3】Javaのクラスが多過ぎるとear/warアプリが起動しなくなる 事象 ホスト(メインフレーム)・モダナイでは、諸般の事情で、war1つあたりにデプロイされるクラスの数が膨大にな ることが少なくない。

    あるホスト・モダナイ案件では、開発期間中のある時期に、サイズが2.7GBや1.5GBのearファイルをデプロイし ようとすると、Webアプリの起動中に大量のメモリを消費しながら、2時間以上かけて、起動が完了するという事 象が発生。 ※ジョブスケジューラ からのジョブ実行 JOB PARAM定義 XML JP1/AJS3 エージェント DAM部品 DB部品 リライトAP (業務プログラム) 元COBOL 元EASY 元ユーティリティ 元アセンブラ Shell Script jBatch JSL ジョブ管理 サーバ JP1 帳票 ユーティリティ 商用Java EE AP サーバー 某W〇〇 L〇〇〇〇〇〇 NDB DAM 運用管理 システム 業務プログラム COBOL EASY アセンブラ ユーティリティ DAM部品 DB部品 ACS コントロール 帳票 ユーティリティ PRT 帳票 SPOOL ライタ JCL OSⅣ/MSP オペレーティングシステム AIM/JES ※系列間 リモートジョブ実行 他系列 NJE 2025年以前 2026年以降 モダナイゼーション リライトAPのクラスが58万個以上。 earファイルのサイズが1.5~2.7GB
  21. © 2026 Accenture All Rights Reserved TIPS【3】Javaのクラスが多過ぎるとear/warアプリが起動しなくなる 原因 当事象の原因の一つ: 業務アプリというだけで一律に必要のないものまで、CDI管理Beanにしていた。

    beans.xmlがアプリケーション初期化ライフサイクルにどう作用しているのかを知る必要があった。 【参考文献】JSR 365: Contexts and Dependency Injection for Java 2.0 > 12. Packaging and deployment https://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#packaging_deployment デプロイメント時にCDIコンテナは次のようなフローでロード済みのクラスを読み込み、初期化処理を行う。 大量のクラスがBean検出(Bean Discovery)されることが、起動の遅延につながった デプロイメント時におけるCDIコンテナによるアプリケーションの初期化フロー ① 各 サ ー ビ ス プ ロ バ イ ダ ー 初 期 化 ② 検 出 事 前 処 理 ④ 型 検 出 事 後 処 理 ⑦ デ プ ロ イ メ ン ト 問 題 検 出 ⑧ デ プ ロ イ メ ン ト 検 証 事 後 処 理 ⑥ 検 出 事 後 処 理 ⑨ ア プ リ ケ ー シ ョ ン へ の リ ク エ ス ト の 送 信 を 開 始 ③型検出の実行 検出対象のクラスファイルのサイズや数が 多くなればなるほど、時間がかかる ⑤ 検出の実行 情報の収集/登録 クライアントプロキシの設定 など ③で検出された型が多ければ多いほど、 時間は掛かり、メモリも消費する
  22. © 2026 Accenture All Rights Reserved TIPS【3】Javaのクラスが多過ぎるとear/warアプリが起動しなくなる 解決策 beans.xmlのbean-discovery-modeの指定を見直した。 

    bean-discovery-mode:allを非推奨または廃止  CDI管理Beanにはスコープのアノテーションを宣言し、クラスライブラリのbean-discovery- mode:annotatedを指定  CDI管理Beanであることが不要なリライトAPクラスのライブラリのbean-discovery-mode:noneを指定 Beanディスカバリモードの振る舞い モード名 • 引数なしコンストラクタを持つすべてのクラスをCDI管理Beanとする。 bean-discovery- mode=“all” • Bean定義アノテーションが付与されているクラスのみ、CDI管理Beanとする。 • beans.xmlを含まない場合(暗黙的Beanアーカイブ)のデフォルト bean-discovery- mode=“annotated” • アーカイブに含むすべてのクラスをCDI管理Beanとして扱わない。CDIによる管 理対象外とする。 bean-discovery- mode=“none”
  23. © 2026 Accenture All Rights Reserved TIPS【3】Javaのクラスが多過ぎるとear/warアプリが起動しなくなる 解決策 ③型検出の実行 ⑤

    検出の実行 CDI管理Beanが不要なBeanアーカイブ bean-discovery-mode=“ none”の beans.xml CDI管理Beanが必要なBeanアーカイブ bean-discovery-mode=“ annotated” のbeans.xml Beanアーカイブ(クラスライブラリのjar)内のMETA-INF/beans.xmlに対し、 bean-discovery-modeをnoneと設定することで、 不要なクラスをCDIコンテナが検出しなくなり、起動時間や起動時の消費メモリが改善された
  24. © 2026 Accenture All Rights Reserved TIPS【3】のデモ 次のWebアプリケーションのMETA-INF/beans.xmlを確認し、bean-discovery-modeがnoneになっている ことを確認。 このWebアプリケーションをJBoss

    EAPにデプロイし、インジェクションが機能しなくなることを確認。 jjugnsjeecditips202602/febtips03: bean-discovery-mode="none"の動作確認
  25. © 2026 Accenture All Rights Reserved TIPS【4】 Dependentスコープのインスタンスがメモリ解放されない 事象 jBatchのジョブやオンライン処理を走らせ続けると、ヒープメモリの使用量が下がらずに上限に近づき続けた。

    ヒープダンプを解析したところ、RequestScopedスコープのBeanインスタンスは解放されているにもかかわらず、 DependentスコープのBeanインスタンスが解放されていないことが判明。 ネットで検索したところ、同じようなトラブルを見つけた。 https://github.com/quarkusio/quarkus/issues/5209 Issue5209に対する投稿 it's the responsibility of the client to destroy @Dependent instances manually through Instance.destroy() 訳: Dependentスコープのインスタンスを Instance.destroy()で手動で破棄 するのは、アプリ側(the client)の責務 である。 https://stackoverflow.com/questions/45294758/do-we-need-to- destroy-a-cdi-bean-obtained-programmatically question45294758に対する投稿 you didn't really inject it, instead you did programmatic lookup. Therefore, it isn't bound to any other bean and you should destroy it. 訳: あなたは実際にはDependentのインスタンスをインジェクトせ ず、代わりにプログラマティックなルックアップを行った。 だから、それは他のノーマルスコープのインスタンスに紐づいてい ないし、あなたはそれを(手動で)破棄すべきだ。
  26. © 2026 Accenture All Rights Reserved TIPS【4】のデモ 次のWebアプリをJBoss EAPにデプロイ。 jjugnsjeecditips202602/febtips04:

    CDI.current().select(クラスobject).get()という方法で動的に 取得したDependentスコープのインスタンスがメモリ解放されない 次のURLをブラウザで20回連続で打ち込み、RequestScopedスコープのBeanを動的取得しても OutOfMemoryが起きないことを確認。 http://localhost:8080/febtips04-0.0.1-SNAPSHOT/rest4/rqst 続いて、次のURLを連続で打ち込み、DependentスコープのBeanを動的取得すると、OutOfMemoryが起き ることを確認。 http://localhost:8080/febtips04-0.0.1-SNAPSHOT/rest4/dpndnt
  27. © 2026 Accenture All Rights Reserved TIPS【4】 Dependentスコープのインスタンスがメモリ解放されない 原因 Dependentのインスタンスを、CDI.current().select(クラスobject).get()という方法で、動的に取

    得していたことが大きな原因。 CDIの仕様文書で次のように書かれている。 https://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#bm_obtain_instance Instances of dependent scoped beans obtained with this Instance object must be explicitly released by calling Instance.destroy() method. 意訳: javax.enterprise.inject.Instanceオブジェクトにより取得されたDepedentスコープBeanのインスタ ンスは、javax.enterprise.inject.Instance#destroy()メソッドを呼ぶことにより明示的 に解放される必要がある。 TIPS【1】で述べたように、ノーマルスコープのBeanに関しては、コンテキストとクライアントプロキシによりライ フサイクル管理されているため、これで取得するのは問題が無い。 しかし、DependentスコープのBeanをこの方法で取得した後、個別にCDI.current().destroy()メ ソッドで、解放処理を行う必要があるということ。
  28. © 2026 Accenture All Rights Reserved CDIの動的取得とは 共通部品として、クラス名などのコンポーネントを特定するFQCNを引数にして、それに対応するBeanを取得した いときがある。 例)イベント駆動エンジンで、受信するメッセージの種類に応じて、数百から数千のビジネスロジックのCDIビーン

    を動的に取得し、実行させたい。 javax.enterprise.inject.InstanceというAPIを使用すると、インジェクションを経由せずに、CDIコンテナに該 当Classインスタンスをlookupすることで、そのBeanインスタンスを取得できる。 使い方としては次の通り、 ①Java EEサーバーから提供されているCDIコンテナにアクセスできるCDIインスタンスを取得する。 CDI<Object> current = CDI.current(); ② そのCDIインスタンスのselectメソッドに取得したいBeanのクラスオブジェクトを引数として渡し、 javax.enterprise.inject.Instanceを取得する(上記の例では、メッセージの種類に応じたFQCNを登録済にする)。 javax.enterprise.inject.Instance<Sample> instnc = current.select(Sample.class); ③ javax.enterprise.inject.Instanceのget()メソッドを実行し、CDIコンテナからクラス名に該当する Sample sample = instnc.get(); ①~③を縮めて、CDI.current().select(クラス).get()と書くことができる。 ※Spring Frameworkで似たような用途を実現する場合、 ApplicationContextAwareというAPIを使用する。
  29. © 2026 Accenture All Rights Reserved TIPS【4】 WeldのCreationalContextImpl.javaの実装を確認 WeldのCreationalContextImpl.javaのソースコードを確認すると、 https://github.com/weld/core/blob/2.4.8.Final/impl/src/main/java/org/jboss/weld/context/CreationalContextImpl.java

    Dependentスコープのインスタンスを格納するためのListオブジェクトフィールドを持ち、 DependentBeanインスタンスをそのListフィールドに追加するメソッドや、解放するメソッドが実装されている。 CDI.current().select().get()を実行すると、 dependentインスタンス格納用Listに 生成されたものが格納されている。 CreationalContextImplのdependencesフィー ルドがDependentスコープインスタンスの ContextualInstanceを参照し続けるため、GCに掛から なくなり、OutOfMemoryが発生する。 CDI.current().destroy()を実行すると、 dependentインスタンス格納用Listの参照 から解放されている。
  30. © 2026 Accenture All Rights Reserved Dependentインスタンスはなぜdestroyが必要なの? 申し訳ないが、当方としても、その疑問はまだ解消されていない。ただ、Dependentスコープだから、即、 dependencesに参照され続けるわけではない。 このようなコードだとCreationalContextImplに参照され続ける

    このようなコードだと org.jboss.weld.contexts.unbound.DependentContextImplの addDependentInstanceメソッドで creationalContext.getDependentInstances().isEmpty()がtrueを返す。 即ち、 CreationalContextImpl.dependentInstancesに格納されていないこ とがわかる。 両者の違いはAOPのアノテー ション宣言の有無 org.jboss.weld.contexts.unbound.Dep endentContextImplの addDependentInstanceメソッドで Dependentインスタンスが SerializableContextualInstanceImp lにラップされて、dependentInstancesに 追加される。
  31. © 2026 Accenture All Rights Reserved TIPS【4】 Dependentスコープのインスタンスがメモリ解放されない 解決策 動的取得したDependentスコープのBeanを使い終わった後に必ず通る場所で、

    CDI.current().destroyに渡す。 TIPS4用HelloTips04#destroyCDIDependentBeanでは念のために org.jboss.weld.bean.proxy.ProxyObject のDependentスコープBeanに絞って、 destroyメソッドに渡すように実装した。 febtips04/src/main/java/io/github/futokiyo/febtips04/rest/HelloTips04.java at main · jjugnsjeecditips202602/febtips04
  32. © 2026 Accenture All Rights Reserved TIPS【4】 Dependentスコープのインスタンスがメモリ解放されない 教訓 ①CDIの動的取得(CDI.current().select(クラスobject).get())には、このよう

    な副作用があることを認識するべき。 ②理想論かもしれないが、Beanの役割・責務を考慮して、Beanスコープは決める べき。 例)状態を持たないことが確実ー>ApplicationScoped HttpRequestのライフサイクルならば、RequestScoped HttpSessionのライフサイクルならば、SessionScoped 「よくわからないから、とりあえず、Dependentにしておく」というのは、楽だが、このような副作用をもたらす可 能性があることを認識しておくべき。 ③インジェクションで出来ることは、インジェクションで実現する。 ④どうしても、使いたいのであれば、使い終わり次第、確実に CDI.current().destroyで破棄するようにする。
  33. © 2026 Accenture All Rights Reserved 動的取得(CDI.current().select().get())のメリット/デメリット 1. メリット 1.

    インジェクションさせることなく、FQCNの文字列やClassインスタンスにより、CDIのBeanインスタン スを取得できる。 1. アプリ・アーキテクチャ側で、汎用的なBeanインスタンス生成処理を実装するときに便利。 2. デメリット 1. 多用すると、影響範囲が追い辛くなることがある。 2. JUnitで単体テストを実装する場合に、Mockitoでモックを実装する必要がある。 1. モックを実装する工数が発生する。 2. テスタビリティ(テストの容易性)が落ちる。 3. JEE規格上、DependentスコープのBeanを動的取得するの際はCDI.current().destroyメ ソッドで解放することになっている。何らかの事情でこれが実施されないとメモリリークにつながる。 想定されるケース①:最初はRequestスコープで実装し本番稼働を迎えたが、保守の途中で Dependentに変えた際、destroy呼び出しを実装し忘れた。 想定されるケース②:例外を投げると、destroyが呼び出されなくなる。
  34. © 2026 Accenture All Rights Reserved まとめ  CDIのインジェクションを使いこなすには、コンテキストとクライアントプロキシの理解が大事。 ※SpringFWでSingletonスコープ・ビーンのフィールドにRequestスコープ・ビーンを定義すると、コンパイルは通るが、

    デプロイ時にScopeNotActiveExceptionが発生する。 febtips02springcglib/SingletonがRequestScopeを持つと起きるエラー.txt at main · jjugnsjeecditips202602/febtips02springcglib  CDI Beanのデフォルト・スコープはDependentだが、Spring FWの場合はSingletonスコープ。逆 な事に注意  インターセプターの動作原理をある程度理解しておく方が良い。アノテーションを付けるだけで、動くよう になるわけではない。  beans.xmlは、Bean検出(Bean Discovery)の制御を担っている。  インジェクションで実現できることはインジェクションを使用する。特に理由もなく動的取得を使って いる場合、コード・レビュー時にメモリリークの危険性や脆弱性を指摘し、インジェクションを使用す るように修正させる。  動的取得 CDI.current().select(クラス).get()はむやみに使うべきではない。どうしても使用する 必要があるならば、DependentスコープのBeanの破棄を確実に漏れなく行うように設計・実装 する事。  デフォルトだからという理由で、とりあえずDependentスコープにしない。Beanスコープは何が適切か を要件に応じて、都度、検討することが理想的。  CDI実装であるWeldを意識する方が良い。APIやソースコードの理解が必要になることがある。
  35. © 2026 Accenture All Rights Reserved © 2026 Accenture All

    Rights Reserved ご清聴ありがとうございました!
  36. © 2026 Accenture All Rights Reserved 豆知識:WELDって何? WeldとはいくつかあるCDI実装の中の一つ。 CDIとは前述の通りJava EE/Jakarta

    EE内のDI仕様に過ぎない。 OpenLiberty, WildFlyなど多くのJEEコンテナやAPサーバーで採用されているCDIの実 装クラスライブラリ群が「Weld」 https://weld.cdi-spec.org/ CDIには、他に次の実装が存在している。 ・Quarkus ArC ・ Apache OpenWebBeans ・ Caucho. Resin CanDI ・ Google Guice