Java EEベースの製品を作成しています。この製品では、 GlassFish 3とEJB 3.1を使用しています。
私のアプリケーションには、スケジューラー セッションBean があり、Webサービスを使用しています。最近、 Apache TomEE について知りました。これは Contexts and Dependency Injection(CDI) をサポートしています。 GlassFishコンテナはCDIもサポートしています。
CDIがまだ提供していない機能を必要としないセッションBeanを置き換えることはできますか?もしそうなら、私が得ることができる利点は何ですか?
はい、CDIとEJBの両方を自由に組み合わせて、素晴らしい結果を得ることができます。 @WebService
と@Schedule
を使用しているように聞こえますが、これらはEJBをミックスに追加する良い理由です。
そこには多くの混乱がありますので、EJBとCDIが互いに関連する一般的な情報を以下に示します。
EJB are CDI Beanであるため、CDIのすべての利点があることに注意してください。その逆は(まだ)真実ではありません。そのため、「EJB vs CDI」という考え方は、「EJB + CDI vs CDI」という奇妙な方程式に実際に変換されるため、絶対に考えないでください。
Java EEの将来のバージョンでは、それらを調整し続けます。調整手段とは、先頭に@Stateful
、@Stateless
、または@Singleton
アノテーションがなくても、既にできることを実行できるようにすることです。 。
最終的に、EJBとCDIは、プロキシコンポーネントであるという同じ基本設計を共有します。 EJBまたはCDI Beanへの参照を取得するとき、それは実際のBeanではありません。むしろ、与えられたオブジェクトは偽物(プロキシ)です。この偽オブジェクトのメソッドを呼び出すと、呼び出しはコンテナーに送られ、コンテナーはインターセプターやデコレーターなどを介して呼び出しを送信し、トランザクションまたはセキュリティチェックを処理します。すべてが完了すると、呼び出しは最終的に実際のオブジェクトに行き、結果はプロキシを介して呼び出し元に返されます。
違いは、呼び出されるオブジェクトがどのように解決されるかだけです。 「解決」とは、コンテナが実際のインスタンスを呼び出して呼び出す場所と方法を意味するだけです。
CDIでは、コンテナは基本的に特定の期間(リクエスト@RequestScoped
、HTTPセッション@SessionScoped
ごと、アプリケーション@ApplicationScoped
ごと、JSFカンバセーション@ConversationScoped
ごと、またはカスタムスコープの実装ごとに)存在するハッシュマップとなる「スコープ」を探します。 。
EJBでは、Beanのタイプが@Stateful
の場合、コンテナーはハッシュマップも調べます。 @Stateful
Beanは、上記のスコープアノテーションのいずれかを使用して、スコープ内の他のすべてのBeanとともに存続および終了させることもできます。 EJBでは、@Stateful
は基本的に「任意のスコープ」Beanです。 @Stateless
は基本的にインスタンスプールです。1回の呼び出しの間、プールからインスタンスを取得します。 @Singleton
は基本的に@ApplicationScoped
です
したがって、基本的なレベルでは、「EJB」Beanでできることはすべて、「CDI」Beanでできるはずです。カバーの下では、それらを区別するのは非常に困難です。インスタンスの解決方法を除いて、すべての配管は同じです。
現在、このプロキシを行うときにコンテナが提供するサービスの点では同じではありませんが、私が言うようにJava EE仕様レベルで作業しています。
あなたが持っているかもしれない「軽い」または「重い」精神的なイメージを無視してください。それがすべてのマーケティングです。ほとんどの部分が同じ内部設計になっています。 CDIインスタンスの解決は、もう少し動的でコンテキストに依存するため、おそらくもう少し複雑です。比較すると、EJBインスタンスの解決はかなり静的で、愚かで単純です。
TomEEの実装の観点から言えますが、EJBの呼び出しとCDI Beanの呼び出しのパフォーマンスの差はほぼゼロです。
もちろん、メリットがない場合はCDIやEJBを使用しないでください。インジェクション、イベント、インターセプター、デコレーター、ライフサイクルトラッキングなどが必要になったら、CDIを投入します。それはほとんどの時間です。
これらの基本を超えて、@Stateful
、@Stateless
、または@Singleton
を追加してCDI BeanをEJBにする場合にのみ使用できるオプションがある便利なコンテナサービスがいくつかあります。
以下に、EJBを分類する短いリストを示します。
JAX-WS @WebService
を公開しています。私は怠け者。 @WebService
もEJBである場合は、web.xml
ファイルにリストしてサーブレットとしてマップする必要はありません。それは私にとって仕事です。さらに、以下に記載されている他の機能を使用するオプションがあります。だから、私にとっては簡単です。
@Stateless
および@Singleton
でのみ使用可能です。
@Path
を介したJAX-RSリソースの公開。私はまだ怠け者です。 RESTfulサービスもEJBである場合、再び自動検出が行われ、JAX-RS Application
サブクラスまたはそのようなものに追加する必要はありません。さらに、以下で説明する優れた機能のいずれかを使用する場合は、@WebService
とまったく同じBeanを公開できます。
@Stateless
および@Singleton
でのみ使用可能です。
@Startup
を介して起動時にロードします。現在、CDIにはこれに相当するものはありません。どういうわけか、コンテナライフサイクルでAfterStartup
イベントのようなものを追加するのを逃しました。これを実行していた場合、それをリッスンする@ApplicationScoped
Beanがあれば、それは@Singleton
を使用した@Startup
と実質的に同じになります。 CDI 1.1のリストに載っています。
@Singleton
でのみ使用可能です。
@Asynchronous
メソッド呼び出し。スレッドを開始することは、サーバー側の環境では不可です。スレッドが多すぎると、パフォーマンスが著しく低下します。この注釈により、コンテナのスレッドプールを使用して行うことを並列化できます。これはすごい。
@Stateful
、@Stateless
、および@Singleton
で使用できます。
@Schedule
またはScheduleExpression
は、基本的にはcronまたはQuartz
機能です。また、非常に素晴らしい。ほとんどのコンテナは、このためにQuartzを使用しています。ただし、ほとんどの人は、Java EEでの作業のスケジューリングはトランザクションです!データベースを更新してから作業をスケジュールし、その1つが失敗すると、両方が自動的にクリーンアップされます。 EntityManager
persist呼び出しが失敗するか、フラッシュに問題があるため、作業のスケジュールを解除する必要はありません。
@Stateless
および@Singleton
でのみ使用可能です。
もちろん、トランザクションに関する上記の注意事項では、JTA
管理対象EntityManager
を使用する必要があります。これらはプレーンな「CDI」で使用できますが、コンテナ管理のトランザクションがなければ、UserTransaction
コミット/ロールバックロジックを本当に単調に複製できます。
CDI、JSF @ManagedBean
、@WebServlet
、@WebListener
、@WebFilter
などを含むすべてのJava EEコンポーネントで利用可能。ただし、@TransactionAttribute
注釈は、@Stateful
、@Stateless
、@Singleton
のみで利用可能です。
EntityManager
EXTENDED
管理対象EntityManager
を使用すると、EntityManager
トランザクション間でJTA
を開いたままにし、キャッシュされたデータを失うことはありません。適切な時間と場所に適した機能。責任を持って使用してください:)
@Stateful
でのみ使用可能です。
同期が必要な場合、@Lock(READ)
および@Lock(WRITE)
アノテーションは非常に優れています。同時アクセス管理を無料で取得できます。すべてのReentrantReadWriteLock配管をスキップします。同じバケットには@AccessTimeout
があります。これにより、スレッドがBeanインスタンスへのアクセスを取得するまで待機する時間を指定できます。
@Singleton
Beanのみで利用可能です。
ejb 3.1の機能を実際に使用していない場合、答えは簡単です。しかし、あなたの質問は、あなたがそれらに気づかないで恩恵を受けているEJB 3.1の概念があると疑うことを示していると思います。一例として、コンテナはslsbのプールを使用する準備ができているため、jmsおよびデータベース接続をリクエストの一部として挿入する必要はありません。