CDI2.0アップデート	
& クックブック	
2016/05/24 上妻 宜人 (あげつま のりと)	
Java Day Tokyo 2016/Java EE Session 4-C
上妻 宜人 あげつま のりと	
•  SIer技術部門でJavaトラブルシューティングの日々	
•  Java EEについて調べて伝えることが好き	
•  コミュニティ講演	
•  GlassFish.JP, JJUG CCC, Java Day Tokyo 2015 など
本日のコンテンツ	
•  駆け足で振り返るCDI	
•  CDI2.0	
•  CDI + α 	
•  最後に
CDI	Context	and	Dependency	Injec0on	
2009/12	CDI1.0	-	Java	EE	6	
2013/5			CDI1.1	-	Java	EE	7	
2014/4			CDI1.2			(maintenance	release)	
2017/1			CDI2.0	-	Java	EE	8
CDIの目的	
1.	DI/AOPを中心とした疎結合コードの実現	
					@Inject,	@InterceptorBinding,	@Decorator,	Event	
	
2.	コンテキストを持つオブジェクトのライフサイクル管理	
					@RequestScoped,	@SessionScoped,	@Applica0onScoped	...	
3.	EJB	SessionBean	と	JSF	@ManagedBean	の統合
CDI	実装製品	
•  Weld	(参照実装)	-	jboss.org	
•  GlassFish,	WildFly/JBossEAP,	WebLogic	
•  OpenWebBeans	-	Apache	SoZware	Founda0on	
•  WebSphere,	Apache	TomEE
Context	and	Dependency	Injec0on:	
CDI管理Beanの定義	
// ライフサイクル: デプロイ〜アンデプロイまで%
public class Controller {%
%
%
}%
%
%
// ライフサイクル: ユーザセッションごとに生成、ログアウトで破棄%
public class ShoppingCart implements Cart {...}%
%
Context	and	Dependency	Injec0on:	
ランタイム例外を引き起こすコンテキスト操作	
public class Controller { %
...%
HttpSession session = request.getSession();%
session.setAttribute(“shoppingCart”,	new	ShoppingCart());%
%
....%
%
Cart cart = (Cart)session.getAttribute(“shopingCart”);%
Context	and	Dependency	Injec0on:	
CDI管理Beanの定義	
@ApplicationScoped%
public class Controller {%
%
%
}%
%
%
@SessionScoped%
public class ShoppingCart implements Cart {...}%
%
@ApplicationScoped%
public class Controller {%
%
%
}%
%
%
@SessionScoped%
public class ShoppingCart implements Cart {...}%
%
Scope	
•  @RequestScoped	
•  @SessionScoped	
•  @Applica0onScoped	
•  @Conversa0onScoped	
•  @Dependent	
Context	and	Dependency	Injec0on:	
CDI管理Beanのスコープ
Context	and	Dependency	Injec0on:	
@Injectでタイプセーフに取得	
@ApplicationScoped%
public class Controller {%
@Inject%
Cart cart;%
}%
%
%
@SessionScoped%
public class ShoppingCart implements Cart {...}%
%
CDIコンテナがインスタンスをセット
Context	and	Dependency	Injec0on:	
@InterceptorBinding	-		タイプセーフなインターセプタ適用	
Log	 target	
// target%
@ApplicationScope%
public class OrderService {%
public void submit(Order order) {..}%
}%
// Log%
@Interceptor%
public class LogInterceptor {...}%
Context	and	Dependency	Injec0on:	
@InterceptorBinding	-		タイプセーフなインターセプタ適用	
Log	 target	
// target%
@ApplicationScope%
public class OrderService {%
public void submit(Order order) {..}%
}%
// Log%
@Interceptor%
public class LogInterceptor {...}%
@Inherited%
@InterceptorBinding%
@Target({TYPE, METHOD})%
@Retention(RUNTIME)%
public @interface Log {}
Context	and	Dependency	Injec0on:	
@InterceptorBinding	-		タイプセーフなインターセプタ適用	
Log	 target	
// target%
@ApplicationScope @Log%
public class OrderService {%
public void submit(Order order) {..}%
}%
// Log%
@Interceptor @Log%
public class LogInterceptor {...}%
@Inherited%
@InterceptorBinding%
@Target({TYPE, METHOD})%
@Retention(RUNTIME)%
public @interface Log {}	
Binding
CDI1.1の変更点 (Java	EE	7)		
beans.xmlのオプション化	
•  beans.xmlなしでCDI有効化	
•  スコープを持つクラスはすべてCDI管理Bean	
@RequestScoped, @SessionScoped, @ApplicationScoped ...	
•  @Dependentスコープは明示的に付与が必要	
// Java EE 7デフォルトでは@Dependent省略不可%
@Dependent%
public class DependentBean {...}%
CDI1.1の変更点 (Java	EE	7)	
beans.xmlのオプション化	
•  @Priority	
•  主にインターセプタ有効化 & 優先順位付けに使用	
•  Interceptorの有効化にbeans.xmlが不要に	
@Interceptor%
@Priority(Interceptor.Priority.APPLICATION)%
public class LoggingInterceptor { %
@AroundInvoke%
public Object log(InvocationContext ic) %
throws Exception {...}%
}
CDI1.1の変更点 (Java	EE	7)	
@Priorityによるインターセプト順序の定義	
@Interceptor @Timeout%
@Priority(Interceptor.Priority.APPLICATION + 10)%
public class TimeoutInterceptor {...}%
Log	
@Interceptor @Logging%
@Priority(Interceptor.Priority.APPLICATION)%
public class LogInterceptor {...}%
【値が小さいほど早く起動】%
Priority.PLATFORM_BEFORE: 0%
@Transactional = 200%
Priority.LIBRARY_BEFORE: 1000%
Priority.APPLICATION: 2000%
アプリケーション向け有効範囲:〜2999%
Time	
out	 target	
Priority:		2000													2010
CDI1.1の変更点 (Java	EE	7)	
スコープ開始・終了イベント	
@ApplicationScoped%
public class MasterDataCache {%
public void observer(%
@Observes @Initialized(ApplicationScoped.class)%
ServletContext context) {%
// initilize code%
}%
}%
•  スコープの開始・終了タイミングでイベント発火	
•  Applica0onScopedの場合@Startup代わりに使える
CDI1.2の変更点 (Java	EE	7)	
JSR-330との互換性確保	
•  @javax.inject.Singletonをスキャン対象外へ	
•  デフォルトでは@SingletonはCDI管理Beanと見なされない	
•  代わりに @ApplicationScoped を使う	
•  背景はGuavaを含むAPがCDI1.1からデプロイエラーになったこと	
	
Guava	14.0.1	cannot	be	deployed	in	a	JEE7	Container	#1433	
https://github.com/google/guava/issues/1433
本日のコンテンツ	
•  駆け足で振り返るCDI	
•  CDI2.0 	
•  CDI + α	
•  最後に
CDI2.0	(Java	EE	8	/	2017)	
•  	CDI非同期イベント	
•  	仕様をサブセットに分割	
•  	Java	SE	Support	
•  	Java	SE	8	Alignment
@ApplicationScoped%
public class AlertService {%
@Inject AlertRepository repo;%
%
@Transactinal%
public void handleAlert(Alert alert) {%
// 何らかのビジネスロジックを終えた後に ...%
repo.persist(alert);%
}%
}	
通常のメソッド呼び出し	
最初はシンプルな機能	
Alert	
Service	
Alert	
Repository
@ApplicationScoped%
public class AlertService {%
@Inject AlertRepository repo;%
@Inject EmailSender email;%
%
@Transactinal%
public void handleAlert(Alert alert) {%
// 何らかのビジネスロジックを終えた後に ...%
repo.persist(alert);%
email.send(“test@test.com”, alert);%
}%
}	
通常のメソッド呼び出し	
アラートが来たらメールも	...	
Alert	
Service	
Alert	
Repository	
Email	
Sender
@ApplicationScoped%
public class AlertService {%
@Inject AlertRepository repo;%
@Inject EmailSender email;%
@Inject AlertCache cache;%
%
@Transactinal%
public void handleAlert(Alert alert) {%
// 何らかのビジネスロジックを終えた後に ...%
repo.persist(alert);%
email.send(“test@test.com”, alert);%
cache.putIfAbsent(alert);%
}%
}	
通常のメソッド呼び出し	
アラートが来たらキャッシュ更新も	...	
Alert	
Service	
Alert	
Repository	
Email	
Sender	
Alert	
Cache
通常のメソッド呼び出し	
手続き型のデメリット	
•  機能追加毎にクラス間依存性が増加	
•  やがては蜘蛛の巣になる	
•  CDI管理Beanが持つ状態のロールバックが難しい	
•  宣言的トランザクションがコミット失敗した場合、	
トランザクション中に変更したBeanのステートをどう戻すか	
•  catch節で頑張れるが、長くなることも
CDIイベントの振り返り	
イベント発火側のコード	
Alert	
Service	
Alert	
Repository	
Email	
Sender	
Alert	
Cache	
CDI	Event	
@ApplicationScoped%
publilc class AlertService {%
@Inject AlertRepository repo;%
@Inject Event<Alert> event;%
%
public void handleAlert(Alert alert) {%
repo.persist(alert);%
event.fire(alert);%
...%
%
CDIイベントの振り返り	
オブザーバの実装	
Alert	
Service	
Alert	
Repository	
Email	
Sender	
Alert	
Cache	
CDI	Event	
@ApplicationScoped%
publilc class AlertService {%
@Inject AlertRepository repo;%
@Inject Event<Alert> event;%
%
public void handleAlert(Alert alert) {%
repo.persist(alert);%
event.fire(alert);%
...%
@ApplicationScoped%
public class AlertCache {%
...%
public void updateCache(@Observes Alert alert) {%
cache.putIfAbsent(alert.getId(), alert);%
}%
}
CDIイベントの振り返り	
イベントの発火	
Alert	
Service	
Alert	
Repository	
Email	
Sender	
Alert	
Cache	
CDI	Event	
@ApplicationScoped%
publilc class AlertService {%
@Inject AlertRepository repo;%
@Inject Event<Alert> event;%
%
public void handleAlert(Alert alert) {%
repo.persist(alert);%
event.fire(alert);%
...%
@ApplicationScoped%
public class AlertCache {%
...%
public void updateCache(@Observes Alert alert) {%
cache.putIfAbsent(alert.getId(), alert);%
}%
}	
イベントと同じ引数を持つ	
全てのオブザーバに通知
CDIイベントの振り返り	
イベントモデルの一般的な利点	
Alert	
Service	
Alert	
Repository	
Email	
Sender	
Alert	
Cache	
CDI	Event	
Alert	
Service	
Alert	
Repository	
Email	
Sender	
Alert	
Cache	
•  プラグイン構造	
•  既存に手を入れずにObserver追加で拡張	
•  実行タイミング/場所の分離	
•  非同期実行、別マシンでの実行が理論上は可能となる
CDI	
Container	
Subject	
@Observe	
Observer	#1	
@Observe	
Observer	#2	
1.fire()	
2.call	back	#1	
3.call	back	#2
CDI	
Container	
Subject	
@Observe	
Observer	#1	
@Observe	
Observer	#2	
1.fire()	
thread	
2.call	back	#1	
3.call	back	#2	
fire()の完了	
CDI1.2までは同期呼び出しのみ
CDI2.0	#1	
CDI2.0	非同期イベント
CDI2.0	非同期CDIイベント	
イベント発火側の実装	
@ApplicationScoped%
publilc class AlertService {%
%
@Inject Event<Alert> event;%
%
public void handleAlert(Alert alert) {%
event.fire(alert);%
...%
%
CDI2.0	非同期CDIイベント	
イベント発火側の実装	
@ApplicationScoped%
publilc class AlertService {%
%
@Inject Event<Alert> event;%
%
public void handleAlert(Alert alert) {%
event.fireAsync(alert);%
...%
%
CDI2.0	非同期CDIイベント	
イベント発火側の実装	
@ApplicationScoped%
publilc class AlertService {%
%
@Inject Event<Alert> event;%
%
public void handleAlert(Alert alert) {%
event.fireAsync(alert);%
...%
%
CDI2.0	EDR1ではObserver側	
スレッドはコンテナ実装依存	
Weld	3.0.0.Alpha16の場合:		
Weld自体が持つスレッドプールを使用	
(max-size	->	CPUコア数)
CDI2.0	非同期CDIイベント	
コンテナ管理スレッドの利用 (Concurrency	U0li0es	for	Java	EE)	
@ApplicationScoped%
publilc class AlertService {%
%
@Inject Event<Alert> event;%
@Resource ManagedExecutor executor;%
%
public void handleAlert(Alert alert) {%
event.fireAsync(alert, executor);%
...%
%
CDI2.0	非同期CDIイベント	
全オブザーバの終了待ち受け	
@ApplicationScoped%
publilc class AlertService {%
%
@Inject Event<Alert> event;%
@Resource ManagedExecutor executor;%
%
public void handleAlert(Alert alert) {%
CompletionStage<Alert> asyncEvent = %
event.fireAsync(alert, executor);%
// block until complete observes%
asyncEvent.toCompletableFuture().join(); %
...%
%
CDI2.0	非同期CDIイベント	
Observer側の実装	
@ApplicationScoped%
publilc class AlertCache {%
%
ConcurrentMap<Long, Alert> cache = ...;%
%
public void updateCache(@Observes Alert alert) {%
cache.putIfAbsent(alert.getId(), alert);%
}%
} %
CDI2.0	非同期CDIイベント	
Observer側の実装	
@ApplicationScoped%
publilc class AlertCache {%
%
ConcurrentMap<Long, Alert> cache = ...;%
%
public void updateCache(@ObserveAsync Alert alert) {%
cache.putIfAbsent(alert.getId(), alert);%
}%
} %
CDI	
Container	
Subject	
@ObserveAsync	
Observer	#1	
@ObserveAsync	
Observer	#2	
fireAsync()	
call	back	
call	back	
fireAsync()は即座にreturnし、	
各Observerは別スレッドで実行	
Request	thread	
Event	thread
CDI	
Container	
Subject	
@ObserveAsync	
Observer	#1	
@ObserveAsync	
Observer	#2	
call	back	
call	back	
transac0on	#1	
transac0on	#2	
tx	#3	
トランザクション・コンテキストは	
オブザーバに引き継がれない	
Request	thread	
Event	thread	
call	back	
fireAsync()
CDI2.0	非同期CDIイベント	
Observerから例外がスローされたらどうなる?	
@ApplicationScoped%
publilc class AlertService {%
%
@Inject Event<Alert> event;%
@Resource ManagedExecutor executor;%
%
public void handleAlert(Alert alert) {%
CompletionStage<Alert> stage = event%
.fireAsync(alert, executor);%
CDI2.0	非同期CDIイベント	
Comple0onStage.excep0onallyによる例外ハンドリング	
@ApplicationScoped%
publilc class AlertService {%
%
@Inject Event<Alert> event;%
@Resource ManagedExecutor executor;%
%
public void handleAlert(Alert alert) {%
CompletionStage<Alert> stage = event%
.fireAsync(alert, executor)%
.exceptionally(ex -> {%
// observer exception logging%
Arrays.stream(ex.getSuppressed())%
.forEach(e -> System.err.println(e));%
return null;%
}); %
CDI2.0	非同期CDIイベント	
CDI2.0より非同期実行に対応	
CDI1.2		
(Java	EE	7)	
CDI2.0	
(Java	EE	8)	
プラグイン	
(型依存の分離)	
非同期実行	
(実行タイミングの分離)	
○	 ○	
○
CDI2.0	非同期CDIイベント	
@MDBとCDI非同期イベント	
CDI1.2		
(Java	EE	7)	
CDI2.0	
(Java	EE	8)	
JMS	
プラグイン	
(型依存の分離)	
非同期実行	
(実行タイミングの分離)	
メッセージ永続化	
Observerの	
別マシン実行	
○	 ○	
○	
○	
○	
○	
○
CDI1.2		
(Java	EE	7)	
CDI2.0	
(Java	EE	8)	
JMS	
プラグイン	
(型依存の分離)	
非同期実行	
(実行タイミングの分離)	
メッセージ永続化	
Observerの	
別マシン実行	
CDI2.0	非同期CDIイベント	
@MDBとCDI非同期イベント	
○	 ○	
○	
○	
○	
○	
○	
【JMSに付いてくる検討項目】	
XAするならクラッシュリカバリ手順は?	
ポイズンメッセージ対策は?	
メッセージ永続化先は?ファイル or	DB?
CDI2.0	非同期CDIイベント	
@MDBとCDI非同期イベント	
CDI1.2		
(Java	EE	7)	
CDI2.0	
(Java	EE	8)	
JMS	
プラグイン	
(型依存の分離)	
非同期実行	
(実行タイミングの分離)	
メッセージ永続化	
Observerの	
別マシン実行	
考えるべき	
タスクの多さ	
○	 ○	
○	
○	
○	
○	
○	
△
CDI2.0	非同期CDIイベント	
CDI非同期イベントが適するケース	
•  順序性,	依存性のない処理の並列実行	
•  例外時のCDI管理Bean状態ロールバック	
•  トランザクション中に変更したステートを元に戻す	
•  メッセージ永続化が不要	
•  例:	朝からリクエスト時点までの業務統計レポート生成	
•  障害復旧後に永続メッセージから実行しても、既に陳腐化
CDI2.0	#2	
仕様をサブセットに分割
CDI2.0	仕様をサブセットに分割	
CDI	Lite	軽量なサブセットの抽出	
•  CDIを	Java	EE	以外の世界で使ってもらいたい	
•  Android,	組込みデバイス	
•  現状のCDI仕様はJava	EE環境を前提	
•  プロキシベースを前提としない軽量実装	
•  Annota0on	Processingによるコンパイル時依存性解決	
			(Androidでよく使われるDaggerがモデル)	
•  省メモリ、低CPU使用率の実現
CDI2.0	仕様をサブセットに分割	
CDI	Lite	軽量なサブセットの抽出	
CDI	core	
•  DI	-	@Inject,	Qualifier	
•  @Produces	
•  Event	&	@Observes	
•  疑似スコープ	
				@Dependent,	@Singleton	
•  Programa0c	lookup	
•  Portable	Exten0on	
CDI	Java	SE	
•  Bootstraping	API	
•  Scope	in	Java	SE	@Applica0onScoped	
•  Packaging	&	deployment	
CDI	Java	EE	
•  Scope	in	Java	EE	
•  @SessionScoped	
•  @Conversa0onScoped	
•  EJBとの連携
CDI2.0	#3	
Java	SE	Support
public static void main(String ... args) {%
try (CDI<Object> cdi = CDI.getCDIProvider().initialize()) {%
Service service = cdi.select(Service.class).get();%
service.doSomething(); %
}%
}%
%
public class ServiceImpl implements Service {%
@Inject %
Repository repo;%
%
public void doSomething() {...}%
}%
CDI2.0	Java	SE	Support	
Java	SE	Bootstrap	API		
CDIコンテナ初期化	
InjectされたBeanの取得
CDI2.0	Java	SE	Support	
“仕様”として含める背景	
•  Java	EE	仕様間での整合性	
•  JAX-RS	,	JPAは Java	SE	でも利用可能な仕様設計	
•  Weld,	OpenWebBeansで既に実装されていた	
•  実装間で類似APIが複数存在するのはJava	EE思想に反する
CDI2.0	#4	
Java	SE	8	Alignment
CDI2.0	Java	SE	8	Alignment	
InterceptorBuilder:	ラムダ	or	メソッド参照によるインターセプタ	
public class InterceptorBuilder {%
// デプロイ時にCDIコンテナよりコールバック%
void afterBeanDiscovery(@Observes AfterBeanDiscovery event) {%
event.addInterceptor() // return InterceptorBuilder%
CDI2.0	Java	SE	8	Alignment	
InterceptorBuilder:	ラムダ	or	メソッド参照によるインターセプタ	
public class InterceptorBuilder {%
// デプロイ時にCDIコンテナよりコールバック%
void afterBeanDiscovery(@Observes AfterBeanDiscovery event) {%
event.addInterceptor()%
.intercept(InterceptionType.AROUND_INVOKE, this::log)%
%
%
%
%
Object log(InvocationContext ic) {%
// interceptor impl%
}%
}%
@AroundInvoke相当
CDI2.0	Java	SE	8	Alignment	
InterceptorBuilder:	ラムダ	or	メソッド参照によるインターセプタ	
public class InterceptorBuilder {%
// デプロイ時にCDIコンテナよりコールバック%
void afterBeanDiscovery(@Observes AfterBeanDiscovery event) {%
event.addInterceptor()%
.intercept(InterceptionType.AROUND_INVOKE, this::log)%
.priority(Priority.APPLICATION)%
.addBinding(Log.INSTANCE);%
}%
%
Object log(InvocationContext ic) {%
// interceptor impl%
}%
}%
CDI2.0	Java	SE	8	Alignment	
InterceptorBuilder:	ラムダ	or	メソッド参照によるインターセプタ	
public class InterceptorBuilder {%
// デプロイ時にCDIコンテナよるコールバック%
void afterBeanDiscovery(@Observes AfterBeanDiscovery event) {%
event.addInterceptor()%
.intercept(InterceptionType.AROUND_INVOKE, this::log)%
.priority(Priority.APPLICATION)%
.addBinding(Log.INSTANCE);%
}%
%
Object log(InvocationContext ic) {%
// interceptor impl%
}%
}%
CDI2.0	Java	SE	8	Alignment	
InterceptorBuilder:	ラムダ	or	メソッド参照によるインターセプタ	
event.addInterceptor()%
...%
.addBinding(Log.INSTANCE);%
CDI2.0	Java	SE	8	Alignment	
InterceptorBuilder:	ラムダ	or	メソッド参照によるインターセプタ	
event.addInterceptor()%
...%
.addBinding(Log.INSTANCE);%
@Log%
public void target() {...} 	
適用対象メソッドと繋ぐために、	
アノテーションの“インスタンス”を渡す必要がある
CDI2.0	Java	SE	8	Alignment	
InterceptorBuilder:	ラムダ	or	メソッド参照によるインターセプタ	
event.addInterceptor()%
...%
.addBinding(Log.INSTANCE);%
%
@Inherited%
@InterceptorBinding%
@Retention(RUNTIME)%
@Target({METHOD, TYPE})%
public @interface Log {}%
CDI2.0	Java	SE	8	Alignment	
InterceptorBuilder:	ラムダ	or	メソッド参照によるインターセプタ	
event.addInterceptor()%
...%
.addBinding(Log.INSTANCE);%
%
@Inherited%
@InterceptorBinding%
@Retention(RUNTIME)%
@Target({METHOD, TYPE})%
public @interface Log {%
class Literal extends AnnotationLiteral<Log> implements Log {%
private Literal() {}%
}%
final Log INSTANCE = new Literal();%
}%
CDIのAnnota0onLiteralクラスを継承して	
アノテーションの”インスタンス”を取得
CDI2.0	Java	SE	8	Alignment	
InterceptorBuilder:	ラムダ	or	メソッド参照によるインターセプタ	
event.addInterceptor()%
...%
.addBinding(Log.INSTANCE);%
%
@Inherited%
@InterceptorBinding%
@Retention(RUNTIME)%
@Target({METHOD, TYPE})%
public @interface Log {%
class Literal extends AnnotationLiteral<Log> implements Log {%
private Literal() {}%
}%
final Log INSTANCE = new Literal();%
}%
@Log%
public void target() {...} 	
Interceptor	Binding
CDI2.0	Java	SE	8	Alignment		
InterceptorBuilderのメリット	
•  1クラスで複数のインターセプタ定義が可能	
•  クラスが冗長に増えるのを防ぐ	
•  Java	EEの何でもアノテーション状態の改善	
•  Java	5	から:	アノテーションをスキャンしてコンテナ機能を付与	
•  Java	8	から:	ラムダを渡すとコンテナが機能付与
CDI2.0	ロードマップ	
スケジュール	
•  2015/6:	Early	DraZ	Review	1		
•  hkps://docs.jboss.org/cdi/spec/2.0.EDR1/cdi-spec.html	
•  2016/6:	Early	DraZ	Review	2	予定	
•  2016/12	〜	2017/1:	CDI2.0	Final	予定	
•  2017上半期	Java	EE	8	リリース 予定
本日のコンテンツ	
•  駆け足で振り返るCDI	
•  CDI2.0 	
•  CDI + α	
•  最後に
DI/AOPが標準化され、非同期イベントが入るのはわかった。	
でも、まだ Spring	より足りないのでは?
Spring	Framework	
@Autowired,	@Aspect%
CDI	(Java	EE)	
@Inject,	@Interceptor	DI/AOP	
プロパティ管理	
@Value,
@PropertySource%
Java起動引数による	
プロファイル切替	
@Profile
CDIは『材料』のみ提供して、	
自作が必要なユースケースも多い	
Spring	Framework	
@Autowired,	@Aspect%
CDI	(Java	EE)	
@Inject,	@Interceptor	DI/AOP	
プロパティ管理	
@Value,
@PropertySource%
@Producesによる要自作	
Java起動引数による	
プロファイル切替	
@Profile	 @Alternativeによる要自作
CDI2.0(2017年)に向けて議論中ではある	
Spring	Framework	
@Autowired,	@Aspect%
CDI	(Java	EE)	
@Inject,	@Interceptor	DI/AOP	
プロパティ管理	
@Value,
@PropertySource%
@Producesによる要自作	
Java起動引数による	
プロファイル切替	
@Profile	
CDI-504:	have	a	standard	CDI	annota0on	like	@ConfigProperty	from	deltapsike	
hkps://issues.jboss.org/browse/CDI-504	
CDI-539:	Support	for	'profile'	in	CDI	
hkps://issues.jboss.org/browse/CDI-539	
【Issue	CDI-504】	
@Alternativeによる要自作	
【Issue	CDI-539】	
・ その機能は本当に『CDI』か?	
				過去例:	
						@Transac0onalをCDIではなくJTAへ	
・ やはり	Configra0on	JSR	では?
CDI2.0(2017年)に向けて議論中ではある	
CDI	(Java	EE)	
@Inject,	@Interceptor	
プロパティ管理	
@Value,
@PropertySource%
@Producesによる要自作	
Java起動引数による	
プロファイル切替	
@Profile	
CDI-504:	have	a	standard	CDI	annota0on	like	@ConfigProperty	from	deltapsike	
hkps://issues.jboss.org/browse/CDI-504	
CDI-539:	Support	for	'profile'	in	CDI	
hkps://issues.jboss.org/browse/CDI-539	
【Issue	CDI-504】	
@Alternativeによる要自作	
【Issue	CDI-539】	
Spring	Framework	
@Autowired,	@Aspect%DI/AOP	
・ その機能は本当に『CDI』か?	
				過去例:	
						@Transac0onalをCDIではなくJTAへ	
・ やはり	Configra0on	JSR	では?	
2017年を待てない場合は	
Apache	Deltaspike
“あったらいいな”はDeltaspikeにある	
Spring	Framework	
@Autowired,	@Aspect%
CDI	(Java	EE)	
@Inject,	@Interceptor	DI/AOP	
プロパティ管理	
@Value,
@PropertySource%
org.apache.deltaspike.core.api.config.%
@ConfigProperty	
Java起動引数による	
プロファイル切替	
@Profile	
org.apache.deltaspike.core.api.projectstage	
ProjectStage%
Apache	Deltaspike
Apache	Deltaspike	
便利なCDI拡張ライブラリ		
•  CDIのPortable	Exten0onを活かしたライブラリ	
•  Seem3	+	My	Faces	CODI	+	α	を統合	
•  2014/6:	1.0.0	リリース (2016/4	現在	1.6.1が最新)
Apache	Deltaspike	#1	@ConfigProperty	
@ConfigPropertyによるパラメータ注入		
@ApplicationScoped%
public class RemoteConnector {%
%
@Inject%
@ConfigProperty(name="remotehost", defaultValue="localhost:8080")%
private String remotehost;%
...%
META-INF/apache-deltaspike.proper0es	
remotehost=192.168.1.2	
DeltaspikeによりInject	
デフォルトのプロパティファイル
Apache	Deltaspike	#1	@ConfigProperty	
任意のプロパティファイルの適用	
@Dependent%
public class MyAppFileConfig implements PropertyFileConfig {%
@Override%
public String getPropertyFileName() {%
return "META-INF/application.properties";%
}%
%
@Override%
public boolean isOptional() {%
return false;%
}%
}
Apache	Deltaspike	#1	@ConfigProperty	
環境変数による値の差し替え	
@Inject%
@ConfigProperty(name="remotehost”,defaultValue="localhost:8080")%
private String remotehost;%
【優先順位】	
1.  環境変数	
export	remotehost=192.168.1.2	
2.  システムプロパティ	
java	-Dremotehost=192.168.1.4	
3.  JNDI	
new InitialContext().bind(“remotehost”, “192.168.1.5”)	
4.  プロパティファイル
Apache	Deltaspike	#2	ProjectStage	
起動オプションで有効なBeanを切り替える	
Service	 Repository	
【development】	
H2		
【produc0on】	
PostgreSQL	
META-INF/persistence.xml%
<?xml version="1.0" encoding="UTF-8"?>%
<persistence>%
<persistence-unit name="h2”>...</persistence-unit>%
<persistence-unit name="PostgreSQL”>...</persistence-unit>%
</persistence>
Apache	Deltaspike	#2	ProjectStage	
起動オプションで有効なBeanを切り替える	
@ApplicationScoped%
public class Repository {%
@PersistenceContext(unitName = “h2 or PostgreSQL??”)%
private EntityManager em;%
...%
}
Apache	Deltaspike	#2	ProjectStage	
Development環境向けEn0tyManagerのBean定義	
@ApplicationScoped%
public class Repository {%
@PersistenceContext(unitName = “h2 or PostgreSQL??”)%
private EntityManager em;%
...%
} 	
@Exclude(exceptIfProjectStage = ProjectStage.Development.class)%
@ApplicationScoped%
public class DevEntityManagerProducer {%
@Produces%
@PersistenceContext(unitName = "h2")%
private EntityManager em; %
}
Apache	Deltaspike	#2	ProjectStage	
Development環境向けEn0tyManagerのBean定義	
@ApplicationScoped%
public class Repository {%
@Inject%
private EntityManager em;%
...%
} 	
@Exclude(exceptIfProjectStage = ProjectStage.Development.class)%
@ApplicationScoped%
public class DevEntityManagerProducer {%
@Produces%
@PersistenceContext(unitName = "h2")%
private EntityManager em; %
}
Apache	Deltaspike	#2	ProjectStage	
システムプロパティで有効プロファイルを指定	
@ApplicationScoped%
public class Repository {%
@Inject%
private EntityManager em;%
...%
} 	
@Exclude(exceptIfProjectStage = ProjectStage.Development.class)%
@ApplicationScoped%
public class DevEntityManagerProducer {%
@Produces%
@PersistenceContext(unitName = "h2")%
private EntityManager em; %
}	
java	-Dorg.apache.deltaspike.ProjectStage=Development	
Repository	 H2		
PostgreSQL
Apache	Deltaspike	#2	ProjectStage	
Produc0on向けも同様	
@ApplicationScoped%
public class Repository {%
@Inject%
private EntityManager em;%
...%
} 	
@Exclude(exceptIfProjectStage = ProjectStage.Production.class)%
@ApplicationScoped%
public class ProdEntityManagerProducer {%
@Produces%
@PersistenceContext(unitName = ”PostgreSQL")%
private EntityManager em; %
}	
Repository	 H2		
PostgreSQL
Apache	Deltaspike	#2	ProjectStage	
Produc0on向けも同様	
@ApplicationScoped%
public class Repository {%
@Inject%
private EntityManager em;%
...%
} 	
@Exclude(exceptIfProjectStage = ProjectStage.Production.class)%
@ApplicationScoped%
public class ProdEntityManagerProducer {%
@Produces%
@PersistenceContext(unitName = ”PostgreSQL")%
private EntityManager em; %
}	
Repository	 H2		
PostgreSQL	
java	-Dorg.apache.deltaspike.ProjectStage=Produc0on
Apache	Deltaspike	
@ConfigPropertyとProjectStage	
•  2つに共通するメリット	
•  環境変数やJavaシステムプロパティで振る舞いを変更	
•  テスト済warを『修正なし』で複数環境で動作させる	
開発環境	 ステージング環境	 商用環境	
AP	
Server	
DB	
myapp.war	
Simurator	
myapp.war	 myapp.war	
関連システム
本日のコンテンツ	
•  駆け足で振り返るCDI	
•  CDI2.0	
•  CDI + α	
•  最後に
CDI2.0	(Java	EE	8	/	2017)	
•  	CDI非同期イベント	
•  	仕様をサブセットに分割	
•  	Java	SE	Support	
•  	Java	SE	8	Alignment
CDI2.0をもっと知るには	
cdi-spec.org	/	JIRA	/	Weld3.0.0.Alpha	
•  ホームページ (CDI	spec	で検索)	
•  hkp://www.cdi-spec.org	
•  JIRA	
•  hkps://issues.jboss.org/projects/CDI	
•  CDI2.0	EarlyDraZReview	1	の参照実装	
•  Weld	3.0.0.Alpha16	hkp://weld.cdi-spec.org/news/2016/04/28/weld-300Alpha16/	
•  WildFly10に組込み可能なpatchもリリース
最後に	
CDI2.0 ドラフト仕様は今すぐWildFly10で動きます	
ぜひ触ってみてください!	
OracleとJavaは、Oracle	Corpora0on及びその子会社、関連会社の米国及びその他の国における登録商標です。	
文中の社名、商品名等は各社の商標または登録商標である場合があります。

CDI2.0アップデート&クックブック #JavaDayTokyo #jdt2016_4c