36477
JavaEEのCDIとEJBの関係や使い分けについて、混乱しています。

DIをしたい → @RequestScoped等のスコープを指定する（CDI Beanを作る？）アノテーションと、@Injectアノテーションを使う。

トランザクション管理をしたい → @Transactionalアノテーションを使う。

この程度の要件であれば、EJBのアノテーション（@Statelessとか@EJBとか）は、使う理由が無いのですか？  
CDIとEJBとで機能的に重複しているものが多いように感じていますが、どう考えたら良いのでしょうか？  
そもそも「CDIかEJBか」という対比ができるような概念なのかもよく分かっていません。

関連する質問：[@Statelessと@RequestScopedの用途の違い](https://ja.stackoverflow.com/questions/29246/stateless%e3%81%a8requestscoped%e3%81%ae%e7%94%a8%e9%80%94%e3%81%ae%e9%81%95%e3%81%84)
CC BY-SA 3.0
2016-10-13T12:56:12.793
29530
2017-07-18T15:55:39.137
2017-04-13T12:52:39.113
-1
8078
question
java java-ee
CDIとEJBの使い分けについて
英語ですが、次のページが参考になるかもしれません。

[When to prefer EJB over CDI](https://blog.oio.de/2014/02/04/when-to-prefer-
ejb-over-cdi/)

ここでは、「EJB = CDI + container services」とまとめてます。

[Where to use EJB 3.1 and
CDI?](https://stackoverflow.com/questions/13487987/where-to-use-ejb-3-1-and-
cdi)

ここでは、「EJB >= CDI」と言ってます。
CC BY-SA 3.0
2017-06-01T03:13:25.373
35177
2017-06-01T03:13:25.373
21092
29530
answer
> この程度の要件であれば、EJBのアノテーション（@Statelessとか@EJBとか）は、使う理由が無いのですか？

ないです。DI、AOP、トランザクション管理に関しては、既に CDI と JTA だけで対応できますし、多くの場合その方がパフォーマンスも良いです。

古の J2EE は何でもかんでも EJB
に詰め込んでいました。その当時の選択としては間違ってはいなかったのですが、あまりに大きく重くなり過ぎたため、現在では CDI
を筆頭とした周辺の仕様に機能を移管し始めています (最終的には EJB が削除される可能性もあります)。互換性のためしばらくの間は EJB
と代替仕様の共存になるでしょうが、新規開発時には基本的に EJB **ではない** 方の仕様を優先した方が良いでしょう。具体的には、CDI か EJB
かで迷ったときには、特別な理由がなければ CDI を選択した方が得策です。

現時点で EJB にあって他の仕様にはない機能は以下のものになります。これらを使う必要がある場合には **CDI ではなく EJB を選ぶ**
必要があります。

  1. RMI-IIOP と二相コミット → Remote EJB のことです。今どき JAX-RS (REST) があるから不要なのでは？という意見がスペック・リード周辺で強いらしく、代替手段なく削除される可能性があります。
  2. EJB プール → EJB コンテナーは内部に Bean のプールを持っていて、Stateless Bean の再利用をします。リソースの再利用と聞こえはいいですが、実態はプール内の Bean が作成され一定数に達するまで EJB コンテナーは動き出さないので、単にサーバーが重たくなるだけです (サーバーの種類やチューニングの程度によっても変化します)。
  3. Message Driven Bean (MDB) → JCA を使用した外部接続で役に立つ機能で、今のところ代替はされません。ただし、CDI のインターセプターが強化されれば、いずれは置き換えられてしまうかもしれません (Java EE 8 の CDI は、MDB を代替するレベルには達していません)。
  4. 非同期 EJB → EJB の機能としては比較的新しいもので、現時点では代替手段がありません。ただし、これも CDI の強化により置き換えられる可能性はあります。
  5. EJB Timer → これは代替手段がありません。EJB でやるべきではないという意見もありますが…。
  6. EJB セキュリティー → Java EE 8 で Security API が導入されるため、これに置き換えられると考えられます。

> そもそも「CDIかEJBか」という対比ができるような概念なのかもよく分かっていません。

CDI と EJB
は登場した時期も背景も異なるため、本来は全く異質のものですが、結局のところ初期のアプローチこそ異なったものの行き着いた先はだいたい同じだったと言えるでしょう。「CDI
で EJB を代替する」という考え方もそこから来ていると推察されます。

EJB は J2EE が形になる前に登場した、当時流行していた分散コンポーネント技術が出発点で、ネットワーク上に分散したビジネスロジック (EJB) を
WebLogic の T3 プロトコル (RMI-IIOP) でアクセスしようというものでした。その後、同じマシン上の EJB
同士でもアクセスできるように拡張され現在の EJB の原型ができ上がります。EJB
が標準で強力なトランザクション管理を備えているのは、分散環境下におけるデータアクセスでトランザクション管理 (特に二相コミット)
が必須になってくるためです。

CDI は元の名前を Web Beans (JSR 299) といい、基本的には同じマシン上のビジネスロジックについて、JSF、EL、EJB
などをまたがったライフサイクル管理 (Stateless/Stateful をもう少し細かくした感じ)と DI
を実現するためのものでした。その後よりシンプルな DI (JSR 330) との対決と融合を経て CDI となりました (この対決が原因で Java EE
6 のリリースは半年遅れています)。CDI が最初に導入されたのは Java EE 6 ですが、当時の CDI はアノテーションを使用した EJB
とよく似ており、しかも半ばオプショナルに近い形で統合されていたため、明示しないと CDI は有効になりませんでした
(現在は条件こそありますが暗黙的に有効です)。当初の CDI にはトランザクション管理がなく、EJB としてはそこを差別点としていましたが、Java EE
7 で CDI 側 (正確には JTA) に `@Transactional` が導入されたためそれがなくなりました。

Java EE
の乱立したアノテーションを整理するには工夫が必要で、それには人それぞれのやり方があると思います。私の場合はアノテーションが導入されてきた歴史を基準にしています。それは、新しいアノテーションを導入して古いアノテーションの整理を試みようとするケースが散見されることによります。
CC BY-SA 3.0
2017-07-18T15:55:39.137
36477
2017-07-18T15:55:39.137
24083
29530
answer