この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:5
ページ更新者:guest
更新日時:2026-06-11 07:12:00

タイトル: EJB
SEOタイトル: EJB完全ガイド(Stateless/Stateful/Singleton/MDB/CDIとの違い/Spring代替)

この記事の要点
  • EJB (Enterprise JavaBeans) = Java EE / Jakarta EE のサーバサイドコンポーネント仕様
  • 主要種別: Stateless / Stateful / Singleton SessionBeanMessage-Driven Bean
  • JPA Entity はもはや EJB ではない(EJB 3.0 で分離)
  • EJB 3.x で大幅軽量化: アノテーションベース、POJO + メタデータで運用
  • CDI との対比: EJB はトランザクション/プーリング/リモート機能、CDI は DI とスコープ管理。併用が標準
  • 現代の選択: 多くのプロジェクトは Spring Boot 推奨、新規 Jakarta EE は MicroProfile + 軽量 EJB の構成
  • EJB の強み: 宣言的トランザクションプール管理分散通信 (RMI/IIOP)、JTA 統合

EJB とは

EJB (Enterprise JavaBeans) は、Java EE(現 Jakarta EE)におけるサーバサイドの再利用可能コンポーネント仕様です。WebLogic / WildFly / GlassFish / Open Liberty などのEJB コンテナにデプロイされ、トランザクション・セキュリティ・並行制御・プーリングといった非機能要件をコンテナが面倒を見ます。

歴史と現状

世代特徴
EJB 1.x / 2.x1999-2003重厚な XML 記述 / Home/Remote 二重インターフェース / 開発生産性悪い → 不人気
EJB 3.02006アノテーション化、POJO ベース。Entity Bean は JPA として分離
EJB 3.12009Singleton SessionBean、no-interface view、組み込み EJB Container
EJB 3.22013Java EE 7、徐々に CDI へシフト
Jakarta EE 8/9/102019-名前空間が javax.ejbjakarta.ejb、EJB Lite で軽量化

SessionBean の種類

Stateless Session Bean

状態を持たない・最もよく使われる業務ロジック実装。コンテナがプールでインスタンスを使い回します。

import jakarta.ejb.Stateless;
import jakarta.inject.Inject;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;

@Stateless
public class OrderService {

    @PersistenceContext
    private EntityManager em;

    public Order createOrder(Long userId, List<Long> productIds) {
        // メソッド単位で自動的にトランザクション開始/コミット
        Order order = new Order(userId);
        for (Long pid : productIds) {
            Product p = em.find(Product.class, pid);
            order.addItem(p);
        }
        em.persist(order);
        return order;
    }
}

// 呼び出し側
@Inject
private OrderService orderService;

orderService.createOrder(userId, productIds);

Stateful Session Bean

クライアントセッション単位で状態を保持する。ショッピングカートのような用途。

import jakarta.ejb.Stateful;
import jakarta.ejb.Remove;

@Stateful
public class ShoppingCart {

    private final List<Item> items = new ArrayList<>();

    public void addItem(Item item) {
        items.add(item);
    }

    public List<Item> getItems() {
        return List.copyOf(items);
    }

    @Remove  // 呼ばれるとインスタンス破棄
    public void checkout() {
        // ...
    }
}

Singleton Session Bean

アプリ全体で1 インスタンス。設定キャッシュなどに。

import jakarta.ejb.Singleton;
import jakarta.ejb.Startup;
import jakarta.annotation.PostConstruct;

@Singleton
@Startup  // 起動時に初期化
public class ConfigCache {

    private Map<String, String> cache = new ConcurrentHashMap<>();

    @PostConstruct
    public void load() {
        // DB から設定読み込み
    }

    public String get(String key) {
        return cache.get(key);
    }
}

Message-Driven Bean (MDB)

JMS キュー/トピックを受信して非同期処理

import jakarta.ejb.MessageDriven;
import jakarta.ejb.ActivationConfigProperty;
import jakarta.jms.Message;
import jakarta.jms.MessageListener;

@MessageDriven(activationConfig = {
    @ActivationConfigProperty(propertyName = &quot;destinationType&quot;,
                               propertyValue = &quot;jakarta.jms.Queue&quot;),
    @ActivationConfigProperty(propertyName = &quot;destination&quot;,
                               propertyValue = &quot;java:/queue/orders&quot;)
})
public class OrderProcessor implements MessageListener {
    @Override
    public void onMessage(Message msg) {
        // メッセージ処理
    }
}

トランザクション制御

EJB はメソッド単位の宣言的トランザクションを持つのが最大の特徴:

import jakarta.ejb.TransactionAttribute;
import jakarta.ejb.TransactionAttributeType;

@Stateless
public class PaymentService {

    // デフォルトで REQUIRED(既存 TX に参加、無ければ新規)
    public void pay(Order o) { ... }

    // 必ず新トランザクションで(既存 TX を中断)
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void logAuditTrail(Order o) { ... }

    // トランザクション無しで実行
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public List<Order> readReport() { ... }
}

EJB と JPA Entity

かつての EJB 1.x/2.x では Entity Bean も EJB 仕様の一部でしたが、EJB 3.0 以降は JPA (Java Persistence API) として完全分離。Entity は単なる POJO + アノテーションです。

@Entity
@Table(name = "orders")
public class Order {
    @Id @GeneratedValue
    private Long id;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;

    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
    private List<OrderItem> items;

    // getter/setter
}

EJB vs CDI

EJBCDI
用途業務ロジック・TX・分散DI とスコープ管理
トランザクション宣言的 (デフォルト REQUIRED)CDI 単体は無し、@Transactional で対応
プーリングあり (Stateless)無し(Scope に依存)
分散呼び出しRMI/IIOP, EJB Remote 可不可
非同期@AsynchronousCDI Async Events (4.0+)
セキュリティ@RolesAllowedJakarta Security と統合
軽量性重め軽い

現代の Jakarta EE はCDI を主軸に、必要に応じて EJB の機能を借りる構成が主流。

Spring Boot との比較

機能EJBSpring Boot
DI@EJB / @Inject@Autowired
業務ロジック@Stateless@Service
トランザクション暗黙の REQUIRED@Transactional 明示
非同期@Asynchronous@Async + ThreadPool
メッセージングMDB@KafkaListener / @RabbitListener
運用EJB コンテナ必須 (WildFly等)組込 Tomcat / Jetty で単独 JAR
学習コスト高い低〜中

現代における EJB の立ち位置

  • 新規プロジェクトの多くは Spring Boot または Micronaut / Quarkus
  • Jakarta EE 新規案件でも EJB Lite(Stateless / トランザクション のみ)に絞る
  • WebLogic / WAS など商用 EJB コンテナ運用中の既存システムでは現役
  • 軽量化トレンド: マイクロサービス時代、起動の重い EJB は敬遠される傾向
  • 金融・大企業の分散トランザクション (JTA + XA) で残る価値あり

FAQ

Q: EJB はもう使わなくていい?
A: 新規 Greenfield なら Spring Boot で十分です。ただし既存 EJB システムの保守、JTA 分散トランザクション要件、商用 AP サーバ標準化された企業では現役。

Q: @Stateless と Spring の @Service の違いは?
A: @Service は単なる DI 対象。@Stateless はプール管理 + 暗黙トランザクション + リモート呼び出し可。Spring で同等は @Service @Transactional

Q: Stateful Session Bean は使うべき?
A: スケーラビリティ上、分散環境では扱いにくい(クライアント-Bean アフィニティ管理)。マイクロサービスでは Redis セッションや JWT を推奨。