CDIとは何か

はじめに:なぜCDIが重要なのか

CDI(Contexts and Dependency Injection)は、Java EE(現在のJakarta EE)における依存性注入(DI)とコンテキスト管理の標準仕様です。
単なる「DIツール」として扱うのではなく、設計思想・ライフサイクル制御・スコープの概念・イベント駆動型設計までをカバーする重要な仕組みです。

現場でJavaを扱うなら、CDIの理解は避けて通れません。
Springとは違うCDI独自の思想を、本記事で本質から掘り下げます。


CDIの本質:何を解決するために存在するのか

CDIの登場以前、Java EEでは各モジュールが密結合になりがちで、ライフサイクルや依存関係の管理が煩雑でした。
EJB(Enterprise JavaBeans)では重量級すぎ、JSFではBeanの管理に限界がありました。

CDIは以下の課題を解決します:

  • 開発者によるオブジェクト生成・依存解決の負担
  • スコープの管理が開発者任せで複雑化
  • テスト性・モジュール性・拡張性の低下

CDIのコア機能

  • 依存性注入(@Inject)
  • スコープの制御(@RequestScopedなど)
  • ライフサイクル管理
  • イベント駆動型設計(@Observes)
  • インターセプター(AOP的な拡張)
  • DecoratorやProducerによる柔軟なBean定義

CDIによる依存性注入の実装:コード例で理解する

@InjectによるDIの基本


public interface UserRepository {
    void save(User user);
}

@ApplicationScoped
public class UserRepositoryImpl implements UserRepository {
    public void save(User user) {
        // データベースに保存する処理
    }
}

@RequestScoped
public class UserService {

    @Inject
    private UserRepository userRepository;

    public void registerUser(String name) {
        User user = new User(name);
        userRepository.save(user);
    }
}

上記のように、@Injectを使えば依存関係を外部から注入できます。CDIコンテナが実装クラス(UserRepositoryImpl)を自動で解決・注入します。

CDIのスコープ定義

CDIではスコープを定義することで、Beanのライフサイクルをコントロールします。

  • @RequestScoped: 1リクエスト中のみ有効
  • @SessionScoped: セッション単位
  • @ApplicationScoped: 全アプリケーションで共有
  • @Dependent: 呼び出し元に依存(最も軽量)

@RequestScoped
public class LoginController {
    private String username;

    public void login() {
        // 認証処理
    }
}

Producerによる柔軟なBean提供


public class Resources {

    @Produces
    @ApplicationScoped
    public Logger produceLogger(InjectionPoint ip) {
        return Logger.getLogger(ip.getMember().getDeclaringClass().getName());
    }
}

このように、CDIではProducerメソッドを定義することで、外部ライブラリや動的生成が必要なオブジェクトも注入可能です。


イベント駆動型アーキテクチャとCDI

イベント発行と購読


// イベントの定義
public class UserCreatedEvent {
    private final String username;
    public UserCreatedEvent(String username) {
        this.username = username;
    }
    public String getUsername() { return username; }
}

// 発行側
@Inject
private Event<UserCreatedEvent> userCreatedEvent;

public void register(String username) {
    // 登録処理
    userCreatedEvent.fire(new UserCreatedEvent(username));
}

// 受信側
public void onUserCreated(@Observes UserCreatedEvent event) {
    System.out.println("ユーザー登録完了: " + event.getUsername());
}

イベントベースで処理を分離することで、関心の分離(Separation of Concerns)が実現され、疎結合なアーキテクチャ設計が可能になります。


CDIとSpringの設計思想の違い

項目CDI(Java標準)Spring Framework
提供元Jakarta EE標準Pivotal社(独自)
注入方式@Inject(JSR-330)@Autowired(独自)
スコープ管理明示的なコンテキストスコープ柔軟だが設定依存
イベント標準仕様(@Observes)ApplicationEventベース
学習コストやや低い(標準志向)高い(独自機能が多い)

どちらを使うかはプロジェクトの要件によりますが、CDIは「軽量で標準的、かつ明確なライフサイクル管理」が求められる場面に適しています。


まとめ

  • CDIは単なるDIフレームワークではなく、スコープ・イベント・ライフサイクルを統合管理するJava EEの中核仕様
  • 生産性・保守性・拡張性を飛躍的に高める
  • Springとの違いを理解し、標準仕様としてCDIを活かす設計力が必要

現場で通用するJavaエンジニアを目指すなら、CDIの基礎ではなく「本質的な設計意図」まで理解しましょう。

採用情報 長谷川 横バージョン
SHARE