はじめに:なぜ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の基礎ではなく「本質的な設計意図」まで理解しましょう。