4

リクエストまたはトランザクションの最後にいくつかのタスクを実行したい状況があります。より具体的には、そのリクエスト中にいくつかのデータを収集する必要があり、最後にそのデータを使用してデータベースの自動更新を行います。

このプロセスは、可能な限り透過的であるべきです。つまり、これを必要とする EJB のユーザーは、それについて心配する必要はありません。

さらに、プロセスへのエントリ ポイントが複数あるため、正確なコール スタックを制御することはできません。

この目標を達成するために、現在、次のコンセプトを検討しています。

  1. 特定の低レベル操作 (常に呼び出される) が CDI イベントを発生させる
  2. ステートレス EJB はこれらのイベントをリッスンし、イベントを受信するとデータを収集し、スコープ指定された CDI Bean に格納します (リクエスト スコープまたは会話スコープのいずれかで問題ありません)。
  3. リクエストの最後に別のイベントが発生し、スコープ指定された 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 に切り替えることはできません)

更新

これまでにいただいた提案により、次の解決策を思い付きました。

  1. リクエストスコープのオブジェクトを使用してデータを保存します
  2. オブジェクトがそのオブジェクトに初めて格納されたとき、イベントが発生します
  3. リスナーは、トランザクションの終了前に呼び出されます ( @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 に帰属させます - 彼は最も少ない :)

4

3 に答える 3

4

で注釈が付けられたメソッドでジョブを実行し@PreDestroyます。

@Named
@RequestScoped
public class Foo {

    @PreDestroy
    public void requestDestroyed() {
        // Here.
    }

}

Bean インスタンスがコンテナーによって破棄される直前に呼び出されます。

于 2012-06-19T17:02:55.490 に答える
3

あなたが探しているのはSessionSynchronizationです。これにより、EJB はトランザクションのライフサイクルに結び付けられ、トランザクションが完了したときに通知を受け取ることができます。

「リクエストとトランザクション」について言及していますが、具体的にEJBトランザクションまたはアプリケーションに関連付けられた何かを意味するかどうかはわかりません。

しかし、私は EJB トランザクションについて話しているのです。

欠点は、一般的に「すべての」トランザクションに対してではなく、特定の EJB が呼び出されたときにのみ呼び出されることです。しかし、それはとにかく適切かもしれません。

最後に、これらの暫定コールバック領域には注意してください。これらのライフサイクル メソッドでのトランザクションで奇妙なことが起こりました。結局、別のスレッドがJMSなどにコミットするために取得したローカルのメモリベースのキューに物を入れることになりました。欠点は、それらが目前のトランザクションに結び付けられていることです。利点は、それらが実際に機能していたことです。

于 2012-06-19T18:55:38.507 に答える
1

ふぅ、それは複雑なシナリオです:)

あなたがこれまでに試したことを私がどのように理解しているかから、あなたは CDI テクニックをかなり使いこなしています - あなたが欠けている大きなものは何もありません。

エントリ ポイントで会話コンテキストをアクティブ化し (おそらく関連するドキュメントを見たことがあるでしょう)、処理全体でそれを使用できるはずです。独自のスコープを実装することを検討することは、実際には価値があるかもしれません。私は、HTTP リクエストによって呼び出されたのか、EJB リモーティングによって呼び出されたのかわからなかった、遠い関係のシナリオで一度これを行いました。

しかし、正直なところ、これはすべて複雑すぎるように感じます。これは、イベントを相互に通知するインターセプターのかなり壊れやすい構造であり、全体として見ると簡単に破ることができます。

あなたのニーズにより適した別のアプローチがあるのでしょうか?たとえば、トランザクション管理自体をフックして、そこからデータの蓄積を実行することはできますか?

于 2012-06-19T18:40:41.153 に答える