リクエストまたはトランザクションの最後にいくつかのタスクを実行したい状況があります。より具体的には、そのリクエスト中にいくつかのデータを収集する必要があり、最後にそのデータを使用してデータベースの自動更新を行います。
このプロセスは、可能な限り透過的であるべきです。つまり、これを必要とする EJB のユーザーは、それについて心配する必要はありません。
さらに、プロセスへのエントリ ポイントが複数あるため、正確なコール スタックを制御することはできません。
この目標を達成するために、現在、次のコンセプトを検討しています。
- 特定の低レベル操作 (常に呼び出される) が CDI イベントを発生させる
- ステートレス EJB はこれらのイベントをリッスンし、イベントを受信するとデータを収集し、スコープ指定された CDI Bean に格納します (リクエスト スコープまたは会話スコープのいずれかで問題ありません)。
- リクエストの最後に別のイベントが発生し、スコープ指定された CDI Bean 内のデータが処理されます
これまでのところ、ステップ 1 と 2 を実行することができました。
ただし、問題はステップ 3 です。
すでに述べたように、プロセスには複数のエントリ ポイント (Web 要求、スケジュールされたジョブ、またはリモート呼び出しから発生) があるため、次のアプローチを考えました。
3a. CDI 拡張機能はすべての Bean をスキャンし、すべての EJB に注釈を追加します。
3b. 追加されたアノテーションに対してインターセプターが登録されるため、EJB メソッドが呼び出されるたびにインターセプターが呼び出されます。
3c。そのインターセプターの最初の呼び出しは、呼び出されたメソッドが戻った後にイベントを発生させます。
そして、ここに問題があります(これも3番目のステップにあります:)):
インターセプターは、それが最初の呼び出しであるかどうかをどのように知るのでしょうか?
私たちは次のことを考えましたが、今のところどちらもうまくいきませんでした:
- リクエスト/会話スコープの Bean を取得する
- アクティブなコンテキストがないため失敗します
- リクエスト/会話コンテキストを取得し、それをアクティブ化します(後続の呼び出しではコンテキストがアクティブになる必要があるため、最初の呼び出しをマークする必要があります)
- システムが別のリクエスト コンテキストを作成したため、WELD は少なくとも 2 つのアクティブなリクエスト コンテキストになり、これについて不平を言いました。
- コンバージョン コンテキストがアクティブなままか、時期尚早に非アクティブ化されました (理由はまだわかりません)。
- 長時間の会話を開始し、呼び出し後に終了する
- アクティブなリクエスト コンテキストがなかったため、失敗しました :(
まだ試していませんが、推奨されていないように見える別のオプション:
- ThreadLocal を使用して、コンテキスト データを保存するか、少なくともここで説明されているように呼び出しコンテキストの伝播を使用します。
ただし、私の知る限り、リクエストが同じスレッドによって完全に処理されるという保証はありません。したがって、コンテナーが別のスレッドに切り替えることを決定したときに、呼び出しコンテキストの伝播が中断されることさえありませんか?
だから、私と一緒に耐えて、その長い説明をすべて読んでくれたすべての人に感謝します.
これを解決する方法についてのアイデアは大歓迎です。
ところで、これは私たちが使用している(そして切り替えることができない)ソフトウェアコンポーネント/標準の一部です:
- JBoss 7.1.0.Final (WELD および CDI 1.0 とともに)
- EJB 3.1
- Hibernate 3.6.9 (まだ 4.0.0 に切り替えることはできません)
更新:
これまでにいただいた提案により、次の解決策を思い付きました。
- リクエストスコープのオブジェクトを使用してデータを保存します
- オブジェクトがそのオブジェクトに初めて格納されたとき、イベントが発生します
- リスナーは、トランザクションの終了前に呼び出されます (
@Observes(during=BEFORE_COMPLETION)
-thanks, @bkail を使用)
これは今のところ機能しますが、まだ 1 つの問題があります。
また、CDI によって管理され、MBean サーバーに自動的に登録される MBean もあります。したがって、これらの MBean は、注入された EJB 参照を取得できます。
ただし、EJB を呼び出す MBean メソッドを呼び出そうとすると、上記のプロセスが開始され、ContextNotActiveException
. これは、JBoss 内で MBean メソッドの実行時にリクエスト コンテキストが開始されないことを示します。
これは、DI の代わりに JNDI ルックアップを使用してサービスを取得する場合にも機能しません。
これについても何かアイデアはありますか?
更新 2 :
さて、私たちは今それを実行しているようです。
基本的には、前回の更新で説明したことを実行し、独自のスコープとコンテキスト (EJB メソッドが最初に呼び出されたときにアクティブになり、対応するインターセプターが終了したときに非アクティブになる) を作成することで、コンテキストがアクティブにならないという問題を解決しました。
通常、リクエスト スコープで同じことができるはずですが (少なくとも仕様に何も見落としていなければ)、JBoss 7.1 にバグがあるため、MBean から EJB を呼び出したり、スケジュールされたジョブ (JNDI ルックアップを行う)。
インターセプターでは、アクティブなコンテキストを取得しようとし、失敗時に Bean マネージャーに存在するコンテキストの 1 つをアクティブ化することができます (EjbRequestContext
その場合が最も可能性が高いです)。
ただし、カスタム スコープはどの JBoss スコープからも独立している必要があるため、ここで干渉してはなりません。
回答/コメントしてくれたすべての人に感謝します。
では、最後の問題があります。皆さんのおかげで正しい方向に進むことができたので、誰の答えを受け入れる必要がありますか? - 私はそれを自分で解決しようとし、それらのポイントを jan に帰属させます - 彼は最も少ない :)