| この記事の要点 |
|
CDI とは
CDI (Contexts and Dependency Injection for Java) は Jakarta EE 標準の DI(依存性注入)仕様です。Spring の @Autowired に相当するものを、Jakarta EE / MicroProfile の世界では CDI が担います。実装は Weld(WildFly/GlassFish)、OpenWebBeans(TomEE)等。
基本: @Inject
import jakarta.inject.Inject;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class UserService {
@Inject
private UserRepository repo; // フィールド注入
@Inject
private EmailSender sender;
public void register(String email) {
User u = new User(email);
repo.save(u);
sender.send(email, "welcome");
}
}
// コンストラクタ注入(推奨)
@ApplicationScoped
public class UserService {
private final UserRepository repo;
private final EmailSender sender;
@Inject
public UserService(UserRepository repo, EmailSender sender) {
this.repo = repo;
this.sender = sender;
}
}
スコープ
| スコープ | 有効範囲 | 用途 |
|---|---|---|
@ApplicationScoped | アプリ全体で 1 インスタンス | サービス、キャッシュ |
@SessionScoped | HTTP セッション | ログインユーザ情報 |
@RequestScoped | HTTP リクエスト | リクエストコンテキスト |
@ConversationScoped | 会話 (JSF 等) | ウィザード |
@Dependent (既定) | 注入先と寿命同じ | シンプルユーティリティ |
@SessionScoped + Serializable | 必須 |
@SessionScoped
public class UserContext implements Serializable {
private User user;
public User getUser() { return user; }
public void setUser(User u) { this.user = u; }
}
@RequestScoped
public class RequestId {
private final String id = UUID.randomUUID().toString();
public String get() { return id; }
}
@Qualifier で型を区別
同じインターフェースに複数実装があるとき、Qualifier で選択します。
import jakarta.inject.Qualifier;
import java.lang.annotation.*;
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
public @interface Stripe {}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
public @interface PayPal {}
// 実装
@Stripe
@ApplicationScoped
public class StripeProcessor implements PaymentProcessor { ... }
@PayPal
@ApplicationScoped
public class PayPalProcessor implements PaymentProcessor { ... }
// 注入時に指定
@Inject @Stripe
private PaymentProcessor processor;
@Produces で外部依存を Bean 化
自分が書いていないクラス(外部 JAR、設定値)を Bean として登録できます。
import jakarta.enterprise.inject.Produces;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class AppConfig {
@Produces
public DataSource dataSource() {
HikariConfig cfg = new HikariConfig();
cfg.setJdbcUrl("jdbc:postgresql://localhost/app");
return new HikariDataSource(cfg);
}
@Produces @ApplicationScoped
public ObjectMapper jacksonMapper() {
return new ObjectMapper()
.registerModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
@Produces
@ConfigValue("app.api.url")
public String apiUrl(InjectionPoint ip) {
return System.getenv("API_URL");
}
}
// 利用側
@Inject
private DataSource ds;
@Inject
private ObjectMapper json;
@Named とビューレイヤ連携
JSF や式言語 (EL) からアクセスできる名前を付けます。
import jakarta.inject.Named;
import jakarta.enterprise.context.SessionScoped;
@Named("userCtx") // EL: #{userCtx.user}
@SessionScoped
public class UserContext implements Serializable {
private User user;
public User getUser() { return user; }
public void setUser(User u) { this.user = u; }
}
Interceptor(AOP)
@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Logged {}
@Interceptor
@Logged
@Priority(Interceptor.Priority.APPLICATION)
public class LoggingInterceptor {
@AroundInvoke
public Object intercept(InvocationContext ctx) throws Exception {
long start = System.nanoTime();
try {
return ctx.proceed();
} finally {
long ms = (System.nanoTime() - start) / 1_000_000;
System.out.printf("[%s] %d ms%n", ctx.getMethod().getName(), ms);
}
}
}
// 利用
@Logged
public void register(String email) { ... }
Event Bus(疎結合通知)
// イベント定義
public class UserRegistered {
private final long userId;
public UserRegistered(long userId) { this.userId = userId; }
public long getUserId() { return userId; }
}
// 発火側
@ApplicationScoped
public class UserService {
@Inject Event<UserRegistered> event;
public void register(String email) {
User u = repo.save(new User(email));
event.fire(new UserRegistered(u.getId()));
// 4.0+ は event.fireAsync(...) で非同期
}
}
// 観察側(複数 OK、疎結合)
@ApplicationScoped
public class WelcomeEmailListener {
public void onUserRegistered(@Observes UserRegistered e) {
emailSender.send(e.getUserId(), "welcome");
}
}
@ApplicationScoped
public class AnalyticsListener {
public void onUserRegistered(@Observes UserRegistered e) {
analytics.track("signup", e.getUserId());
}
}
beans.xml と Bean 発見モード
| モード | 挙動 | 用途 |
|---|---|---|
all | すべての class を Bean 候補 | 古い CDI 1.0 互換 |
annotated | 明示的アノテーションのみ Bean 化(既定) | ★ 推奨 |
none | CDI 無効化 | パフォーマンス重視 |
<!-- META-INF/beans.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
version="4.0"
bean-discovery-mode="annotated">
</beans>
Spring DI との比較
| 機能 | CDI | Spring |
|---|---|---|
| 注入 | @Inject | @Autowired |
| Bean 定義 | @ApplicationScoped 等 | @Component / @Service |
| Producer / Factory | @Produces | @Bean |
| 条件付き | Extension SPI | @ConditionalOnXxx |
| スコープ | 標準 5 種類 | 標準 5 種類 + カスタム |
| イベント | Event<T> / @Observes | ApplicationEvent / @EventListener |
| インターセプタ | @InterceptorBinding | AspectJ / Pointcut |
| 標準 | Jakarta 仕様、複数実装 | Spring エコ実質単独 |
Jakarta CDI 4.x 主要変更点
- 名前空間:
javax.enterprise.*→jakarta.enterprise.* - 非同期 Observer (
@ObservesAsync) 強化 - Build-Time Compatible Extensions(Quarkus 向け軽量 SPI)
- SE モード(
CDI.current()でアプリ外から起動可能) - Bean 発見
annotatedがデフォルト
FAQ
Q: @Inject でなく @Autowired が使える?
A: Spring の中では使える。CDI / Jakarta EE の中では @Inject (JSR-330) が標準です。
Q: 循環依存はどうなる?
A: コンストラクタ注入では起動時にエラー。Provider<T> や Instance<T> で遅延注入して回避できます。
Q: テストでモック注入したい
A: Arquillian(実コンテナテスト)、Weld SE 単体テスト、または Mockito + コンストラクタ注入。
子ページ
子ページはありません
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- プロジェクトをTomcatプロジェクトとして認識させる方法 2026-10-07 22:32:50
- MySQLの1366 Incorrect string value|Laravelの文字コード・絵文字エラー 2026-10-07 21:54:03
- curlの証明書ホスト名不一致|旧エラー51・現行60の確認と対処 2026-10-07 21:54:03
- LaravelのMassAssignmentException|fillableの原因と安全な対処 2026-10-07 21:54:03
- Eclipse で Tomcat の起動ログがコンソールに出ない時の確認手順 2026-10-07 21:54:02
- MySQLにおける中央値(Median)の導き方(バージョン8未満) 2026-10-07 13:49:45
- getInputForward 2026-10-07 13:41:15
- JSONから配列に変換 2026-10-07 13:41:15
- ビューから値をモデルに格納しコントローラーで受け取る方法 2026-10-07 13:23:41
- Laravelのテーブル作成と定義変更|マイグレーション・up/down・注意点 2026-10-07 13:23:41
- NumPy 配列に要素を追加する方法 (append / concatenate) 2026-10-07 13:23:41
- MariaDB・MySQLで現在日時を取得する方法|NOW・タイムゾーン・保存型 2026-10-07 13:13:36
- 【django】テンプレートで定数を使用する方法 2026-10-07 13:10:15
- Spring BootにおけるApplication.propertiesの環境依存設定の分割方法 2026-10-07 12:09:35
- Not supported for DML operations【Springエラー】 2026-10-07 11:09:38