cdi2.0アップデート&クックブック #javadaytokyo #jdt2016_4c

90
CDI2.0アップデート & クックブック 2016/05/24 上妻 宜人 (あげつま のりと) Java Day Tokyo 2016/Java EE Session 4-C

Upload: norito-agetsuma

Post on 08-Jan-2017

1.514 views

Category:

Software


3 download

TRANSCRIPT

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

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

2016/05/24 上妻 宜人 (あげつま のりと)

Java Day Tokyo 2016/Java EE Session 4-C

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

上妻 宜人 あげつま のりと

•  SIer技術部門でJavaトラブルシューティングの日々

•  Java EEについて調べて伝えることが好き

•  コミュニティ講演

•  GlassFish.JP, JJUG CCC, Java Day Tokyo 2015 など

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

本日のコンテンツ

•  駆け足で振り返るCDI

•  CDI2.0

•  CDI + α

•  後に

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

CDIContextandDependencyInjec0on

2009/12CDI1.0-JavaEE6

2013/5CDI1.1-JavaEE7

2014/4CDI1.2(maintenancerelease)

2017/1CDI2.0-JavaEE8

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

CDIの目的

1.DI/AOPを中心とした疎結合コードの実現@Inject,@InterceptorBinding,@Decorator,Event2.コンテキストを持つオブジェクトのライフサイクル管理@RequestScoped,@SessionScoped,@Applica0onScoped...

3.EJBSessionBeanとJSF@ManagedBeanの統合

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

CDI実装製品

•  Weld(参照実装)-jboss.org

•  GlassFish,WildFly/JBossEAP,WebLogic

•  OpenWebBeans-ApacheSoZwareFounda0on•  WebSphere,ApacheTomEE

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

ContextandDependencyInjec0on:CDI管理Beanの定義

// ライフサイクル: デプロイ〜アンデプロイまで %public class Controller {%%%}%%%// ライフサイクル: ユーザセッションごとに生成、ログアウトで破棄 %public class ShoppingCart implements Cart {...}%%

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

ContextandDependencyInjec0on:ランタイム例外を引き起こすコンテキスト操作

public class Controller { %...% HttpSession session = request.getSession();%

session.setAttribute(“shoppingCart”,newShoppingCart());%% ....%%

Cart cart = (Cart)session.getAttribute(“shopingCart”);%

Page 9: CDI2.0アップデート&クックブック #JavaDayTokyo #jdt2016_4c
Page 10: CDI2.0アップデート&クックブック #JavaDayTokyo #jdt2016_4c

ContextandDependencyInjec0on:CDI管理Beanの定義

@ApplicationScoped%public class Controller {%%%}%%%@SessionScoped%public class ShoppingCart implements Cart {...}%%

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

@ApplicationScoped%public class Controller {%%%}%%%@SessionScoped%public class ShoppingCart implements Cart {...}%%

Scope

•  @RequestScoped

•  @SessionScoped

•  @Applica0onScoped

•  @Conversa0onScoped

•  @Dependent

ContextandDependencyInjec0on:CDI管理Beanのスコープ

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

ContextandDependencyInjec0on:@Injectでタイプセーフに取得

@ApplicationScoped%public class Controller {% @Inject% Cart cart;%}%%%@SessionScoped%public class ShoppingCart implements Cart {...}%%

CDIコンテナがインスタンスをセット

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

ContextandDependencyInjec0on:@InterceptorBinding-タイプセーフなインターセプタ適用

Log target

// target%@ApplicationScope%public class OrderService {% public void submit(Order order) {..}%}%

// Log%@Interceptor%public class LogInterceptor {...}%

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

ContextandDependencyInjec0on:@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 {}

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

ContextandDependencyInjec0on:@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

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

CDI1.1の変更点 (JavaEE7)beans.xmlのオプション化

•  beans.xmlなしでCDI有効化

•  スコープを持つクラスはすべてCDI管理Bean @RequestScoped, @SessionScoped, @ApplicationScoped ...

•  @Dependentスコープは明示的に付与が必要

// Java EE 7デフォルトでは@Dependent省略不可%@Dependent%public class DependentBean {...}%

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

CDI1.1の変更点 (JavaEE7)beans.xmlのオプション化

•  @Priority

•  主にインターセプタ有効化 & 優先順位付けに使用

•  Interceptorの有効化にbeans.xmlが不要に

@Interceptor%@Priority(Interceptor.Priority.APPLICATION)%public class LoggingInterceptor { % @AroundInvoke% public Object log(InvocationContext ic) % throws Exception {...}%}

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

CDI1.1の変更点 (JavaEE7)@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%

Timeout target

Priority:20002010

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

CDI1.1の変更点 (JavaEE7)スコープ開始・終了イベント

@ApplicationScoped%public class MasterDataCache {% public void observer(% @Observes @Initialized(ApplicationScoped.class)% ServletContext context) {% // initilize code% }%}%

•  スコープの開始・終了タイミングでイベント発火

•  Applica0onScopedの場合@Startup代わりに使える

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

CDI1.2の変更点 (JavaEE7)JSR-330との互換性確保

•  @javax.inject.Singletonをスキャン対象外へ

•  デフォルトでは@SingletonはCDI管理Beanと見なされない

•  代わりに @ApplicationScoped を使う

•  背景はGuavaを含むAPがCDI1.1からデプロイエラーになったこと

Guava14.0.1cannotbedeployedinaJEE7Container#1433https://github.com/google/guava/issues/1433

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

本日のコンテンツ

•  駆け足で振り返るCDI

•  CDI2.0

•  CDI + α

•  後に

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

CDI2.0(JavaEE8/2017)•  CDI非同期イベント

•  仕様をサブセットに分割

•  JavaSESupport

•  JavaSE8Alignment

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

@ApplicationScoped%public class AlertService {% @Inject AlertRepository repo;% % @Transactinal% public void handleAlert(Alert alert) {% // 何らかのビジネスロジックを終えた後に ...% repo.persist(alert);% }%}

通常のメソッド呼び出し初はシンプルな機能

AlertService

AlertRepository

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

@ApplicationScoped%public class AlertService {% @Inject AlertRepository repo;% @Inject EmailSender email;%% @Transactinal% public void handleAlert(Alert alert) {% // 何らかのビジネスロジックを終えた後に ...% repo.persist(alert);% email.send(“[email protected]”, alert);% }%}

通常のメソッド呼び出しアラートが来たらメールも...

AlertService

AlertRepository

EmailSender

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

@ApplicationScoped%public class AlertService {% @Inject AlertRepository repo;% @Inject EmailSender email;% @Inject AlertCache cache;% % @Transactinal% public void handleAlert(Alert alert) {% // 何らかのビジネスロジックを終えた後に ...% repo.persist(alert);% email.send(“[email protected]”, alert);% cache.putIfAbsent(alert);% }%}

通常のメソッド呼び出しアラートが来たらキャッシュ更新も...

AlertService

AlertRepository

EmailSender

AlertCache

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

通常のメソッド呼び出し手続き型のデメリット

•  機能追加毎にクラス間依存性が増加•  やがては蜘蛛の巣になる

•  CDI管理Beanが持つ状態のロールバックが難しい

•  宣言的トランザクションがコミット失敗した場合、

トランザクション中に変更したBeanのステートをどう戻すか

•  catch節で頑張れるが、長くなることも

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

CDIイベントの振り返りイベント発火側のコード

AlertService

AlertRepository

EmailSender

AlertCache

CDIEvent

@ApplicationScoped%publilc class AlertService {% @Inject AlertRepository repo;% @Inject Event<Alert> event;% % public void handleAlert(Alert alert) {% repo.persist(alert);% event.fire(alert);% ...% %

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

CDIイベントの振り返りオブザーバの実装

AlertService

AlertRepository

EmailSender

AlertCache

CDIEvent

@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);% }%}

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

CDIイベントの振り返りイベントの発火

AlertService

AlertRepository

EmailSender

AlertCache

CDIEvent

@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);% }%}

イベントと同じ引数を持つ全てのオブザーバに通知

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

CDIイベントの振り返りイベントモデルの一般的な利点

AlertService

AlertRepository

EmailSender

AlertCache

CDIEvent

AlertService

AlertRepository

EmailSender

AlertCache

•  プラグイン構造

•  既存に手を入れずにObserver追加で拡張

•  実行タイミング/場所の分離

•  非同期実行、別マシンでの実行が理論上は可能となる

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

CDIContainer

Subject@Observe

Observer#1@Observe

Observer#2

1.fire()

2.callback#1

3.callback#2

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

CDIContainer

Subject@Observe

Observer#1@Observe

Observer#2

1.fire()

thread

2.callback#1

3.callback#2

fire()の完了

CDI1.2までは同期呼び出しのみ

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

CDI2.0#1

CDI2.0非同期イベント

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

CDI2.0非同期CDIイベントイベント発火側の実装

@ApplicationScoped%publilc class AlertService {% % @Inject Event<Alert> event;% % public void handleAlert(Alert alert) {% event.fire(alert);% ...% %

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

CDI2.0非同期CDIイベントイベント発火側の実装

@ApplicationScoped%publilc class AlertService {% % @Inject Event<Alert> event;% % public void handleAlert(Alert alert) {% event.fireAsync(alert);% ...% %

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

CDI2.0非同期CDIイベントイベント発火側の実装

@ApplicationScoped%publilc class AlertService {% % @Inject Event<Alert> event;% % public void handleAlert(Alert alert) {% event.fireAsync(alert);% ...% %

CDI2.0EDR1ではObserver側スレッドはコンテナ実装依存Weld3.0.0.Alpha16の場合:Weld自体が持つスレッドプールを使用(max-size->CPUコア数)

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

CDI2.0非同期CDIイベントコンテナ管理スレッドの利用 (ConcurrencyU0li0esforJavaEE)

@ApplicationScoped%publilc class AlertService {% % @Inject Event<Alert> event;% @Resource ManagedExecutor executor;% % public void handleAlert(Alert alert) {% event.fireAsync(alert, executor);% ...% %

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

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(); % ...% %

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

CDI2.0非同期CDIイベントObserver側の実装

@ApplicationScoped%publilc class AlertCache {% % ConcurrentMap<Long, Alert> cache = ...;%% public void updateCache(@Observes Alert alert) {% cache.putIfAbsent(alert.getId(), alert);% }%} %

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

CDI2.0非同期CDIイベントObserver側の実装

@ApplicationScoped%publilc class AlertCache {% % ConcurrentMap<Long, Alert> cache = ...;%% public void updateCache(@ObserveAsync Alert alert) {% cache.putIfAbsent(alert.getId(), alert);% }%} %

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

CDIContainer

Subject@ObserveAsyncObserver#1

@ObserveAsyncObserver#2

fireAsync()

callback

callback

fireAsync()は即座にreturnし、各Observerは別スレッドで実行

RequestthreadEventthread

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

CDIContainer

Subject@ObserveAsyncObserver#1

@ObserveAsyncObserver#2

callback

callback

transac0on#1

transac0on#2

tx#3

トランザクション・コンテキストはオブザーバに引き継がれない

RequestthreadEventthread

callback

fireAsync()

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

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);%

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

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;% }); %

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

CDI2.0非同期CDIイベントCDI2.0より非同期実行に対応

CDI1.2(JavaEE7)

CDI2.0(JavaEE8)

プラグイン(型依存の分離)

非同期実行(実行タイミングの分離)

○ ○○

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

CDI2.0非同期CDIイベント@MDBとCDI非同期イベント

CDI1.2(JavaEE7)

CDI2.0(JavaEE8)

JMS

プラグイン(型依存の分離)

非同期実行(実行タイミングの分離)

メッセージ永続化

Observerの別マシン実行

○ ○○

○○○○

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

CDI1.2(JavaEE7)

CDI2.0(JavaEE8)

JMS

プラグイン(型依存の分離)

非同期実行(実行タイミングの分離)

メッセージ永続化

Observerの別マシン実行

CDI2.0非同期CDIイベント@MDBとCDI非同期イベント

○ ○○

○○○○

【JMSに付いてくる検討項目】XAするならクラッシュリカバリ手順は?

ポイズンメッセージ対策は?メッセージ永続化先は?ファイル orDB?

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

CDI2.0非同期CDIイベント@MDBとCDI非同期イベント

CDI1.2(JavaEE7)

CDI2.0(JavaEE8)

JMS

プラグイン(型依存の分離)

非同期実行(実行タイミングの分離)

メッセージ永続化

Observerの別マシン実行考えるべき

タスクの多さ

○ ○○

○○○○△

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

CDI2.0非同期CDIイベントCDI非同期イベントが適するケース

•  順序性,依存性のない処理の並列実行

•  例外時のCDI管理Bean状態ロールバック

•  トランザクション中に変更したステートを元に戻す

•  メッセージ永続化が不要

•  例:朝からリクエスト時点までの業務統計レポート生成

•  障害復旧後に永続メッセージから実行しても、既に陳腐化

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

CDI2.0#2

仕様をサブセットに分割

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

CDI2.0仕様をサブセットに分割CDILite軽量なサブセットの抽出

•  CDIをJavaEE以外の世界で使ってもらいたい•  Android,組込みデバイス

•  現状のCDI仕様はJavaEE環境を前提

•  プロキシベースを前提としない軽量実装

•  Annota0onProcessingによるコンパイル時依存性解決(Androidでよく使われるDaggerがモデル)

•  省メモリ、低CPU使用率の実現

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

CDI2.0仕様をサブセットに分割CDILite軽量なサブセットの抽出

CDIcore

•  DI-@Inject,Qualifier

•  @Produces

•  Event&@Observes

•  疑似スコープ@Dependent,@Singleton

•  Programa0clookup

•  PortableExten0on

CDIJavaSE•  BootstrapingAPI

•  ScopeinJavaSE@Applica0onScoped

•  Packaging&deployment

CDIJavaEE

•  ScopeinJavaEE•  @SessionScoped•  @Conversa0onScoped

•  EJBとの連携

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

CDI2.0#3

JavaSESupport

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

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.0JavaSESupportJavaSEBootstrapAPI

CDIコンテナ初期化

InjectされたBeanの取得

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

CDI2.0JavaSESupport“仕様”として含める背景

•  JavaEE仕様間での整合性•  JAX-RS,JPAは JavaSEでも利用可能な仕様設計

•  Weld,OpenWebBeansで既に実装されていた

•  実装間で類似APIが複数存在するのはJavaEE思想に反する

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

CDI2.0#4

JavaSE8Alignment

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

CDI2.0JavaSE8AlignmentInterceptorBuilder:ラムダorメソッド参照によるインターセプタ

public class InterceptorBuilder {% // デプロイ時にCDIコンテナよりコールバック% void afterBeanDiscovery(@Observes AfterBeanDiscovery event) {% event.addInterceptor() // return InterceptorBuilder%

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

CDI2.0JavaSE8AlignmentInterceptorBuilder:ラムダ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相当

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

CDI2.0JavaSE8AlignmentInterceptorBuilder:ラムダ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% }%}%

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

CDI2.0JavaSE8AlignmentInterceptorBuilder:ラムダ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% }%}%

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

CDI2.0JavaSE8AlignmentInterceptorBuilder:ラムダorメソッド参照によるインターセプタ

event.addInterceptor()% ...% .addBinding(Log.INSTANCE);%

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

CDI2.0JavaSE8AlignmentInterceptorBuilder:ラムダorメソッド参照によるインターセプタ

event.addInterceptor()% ...% .addBinding(Log.INSTANCE);%

@Log%public void target() {...}

適用対象メソッドと繋ぐために、アノテーションの“インスタンス”を渡す必要がある

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

CDI2.0JavaSE8AlignmentInterceptorBuilder:ラムダorメソッド参照によるインターセプタ

event.addInterceptor()% ...% .addBinding(Log.INSTANCE);%%@Inherited%@InterceptorBinding%@Retention(RUNTIME)%@Target({METHOD, TYPE})%public @interface Log {}%

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

CDI2.0JavaSE8AlignmentInterceptorBuilder:ラムダ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クラスを継承してアノテーションの”インスタンス”を取得

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

CDI2.0JavaSE8AlignmentInterceptorBuilder:ラムダ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() {...}

InterceptorBinding

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

CDI2.0JavaSE8AlignmentInterceptorBuilderのメリット

•  1クラスで複数のインターセプタ定義が可能•  クラスが冗長に増えるのを防ぐ

•  JavaEEの何でもアノテーション状態の改善

•  Java5から:アノテーションをスキャンしてコンテナ機能を付与

•  Java8から:ラムダを渡すとコンテナが機能付与

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

CDI2.0ロードマップスケジュール

•  2015/6:EarlyDraZReview1•  hkps://docs.jboss.org/cdi/spec/2.0.EDR1/cdi-spec.html

•  2016/6:EarlyDraZReview2予定

•  2016/12〜2017/1:CDI2.0Final予定

•  2017上半期JavaEE8リリース 予定

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

本日のコンテンツ

•  駆け足で振り返るCDI

•  CDI2.0

•  CDI + α

•  後に

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

DI/AOPが標準化され、非同期イベントが入るのはわかった。

でも、まだ Springより足りないのでは?

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

SpringFramework

@Autowired,@Aspect%

CDI(JavaEE)

@Inject,@InterceptorDI/AOP

プロパティ管理@Value,

@PropertySource%

Java起動引数によるプロファイル切替 @Profile

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

CDIは『材料』のみ提供して、自作が必要なユースケースも多い

SpringFramework

@Autowired,@Aspect%

CDI(JavaEE)

@Inject,@InterceptorDI/AOP

プロパティ管理@Value,

@PropertySource%@Producesによる要自作

Java起動引数によるプロファイル切替 @Profile @Alternativeによる要自作

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

CDI2.0(2017年)に向けて議論中ではある

SpringFramework

@Autowired,@Aspect%

CDI(JavaEE)

@Inject,@InterceptorDI/AOP

プロパティ管理@Value,

@PropertySource%@Producesによる要自作

Java起動引数によるプロファイル切替 @Profile

CDI-504:haveastandardCDIannota0onlike@ConfigPropertyfromdeltapsikehkps://issues.jboss.org/browse/CDI-504

CDI-539:Supportfor'profile'inCDIhkps://issues.jboss.org/browse/CDI-539

【IssueCDI-504】

@Alternativeによる要自作

【IssueCDI-539】

・ その機能は本当に『CDI』か?過去例:@Transac0onalをCDIではなくJTAへ

・ やはりConfigra0onJSRでは?

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

CDI2.0(2017年)に向けて議論中ではある

CDI(JavaEE)

@Inject,@Interceptor

プロパティ管理@Value,

@PropertySource%@Producesによる要自作

Java起動引数によるプロファイル切替 @Profile

CDI-504:haveastandardCDIannota0onlike@ConfigPropertyfromdeltapsikehkps://issues.jboss.org/browse/CDI-504

CDI-539:Supportfor'profile'inCDIhkps://issues.jboss.org/browse/CDI-539

【IssueCDI-504】

@Alternativeによる要自作

【IssueCDI-539】

SpringFramework

@Autowired,@Aspect%DI/AOP

・ その機能は本当に『CDI』か?過去例:@Transac0onalをCDIではなくJTAへ

・ やはりConfigra0onJSRでは?2017年を待てない場合はApacheDeltaspike

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

“あったらいいな”はDeltaspikeにある

SpringFramework

@Autowired,@Aspect%

CDI(JavaEE)

@Inject,@InterceptorDI/AOP

プロパティ管理@Value,

@PropertySource%org.apache.deltaspike.core.api.config.%

@ConfigProperty

Java起動引数によるプロファイル切替 @Profile

org.apache.deltaspike.core.api.projectstage

ProjectStage%

ApacheDeltaspike

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

ApacheDeltaspike便利なCDI拡張ライブラリ

•  CDIのPortableExten0onを活かしたライブラリ

•  Seem3+MyFacesCODI+αを統合

•  2014/6:1.0.0リリース (2016/4現在1.6.1が 新)

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

ApacheDeltaspike#1@ConfigProperty@ConfigPropertyによるパラメータ注入

@ApplicationScoped%public class RemoteConnector {% % @Inject% @ConfigProperty(name="remotehost", defaultValue="localhost:8080")% private String remotehost;% ...%

META-INF/apache-deltaspike.proper0esremotehost=192.168.1.2

DeltaspikeによりInject

デフォルトのプロパティファイル

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

ApacheDeltaspike#1@ConfigProperty任意のプロパティファイルの適用

@Dependent%public class MyAppFileConfig implements PropertyFileConfig {% @Override% public String getPropertyFileName() {% return "META-INF/application.properties";% }%% @Override% public boolean isOptional() {% return false;% }%}

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

ApacheDeltaspike#1@ConfigProperty環境変数による値の差し替え

@Inject%@ConfigProperty(name="remotehost”,defaultValue="localhost:8080")%private String remotehost;%

【優先順位】

1.  環境変数exportremotehost=192.168.1.2

2.  システムプロパティjava-Dremotehost=192.168.1.4

3.  JNDInew InitialContext().bind(“remotehost”, “192.168.1.5”)

4.  プロパティファイル

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

ApacheDeltaspike#2ProjectStage起動オプションで有効な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>

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

ApacheDeltaspike#2ProjectStage起動オプションで有効なBeanを切り替える

@ApplicationScoped%public class Repository {% @PersistenceContext(unitName = “h2 or PostgreSQL??”)% private EntityManager em;% ...%}

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

ApacheDeltaspike#2ProjectStageDevelopment環境向け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; %}

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

ApacheDeltaspike#2ProjectStageDevelopment環境向け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; %}

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

ApacheDeltaspike#2ProjectStageシステムプロパティで有効プロファイルを指定

@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

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

ApacheDeltaspike#2ProjectStageProduc0on向けも同様

@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

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

ApacheDeltaspike#2ProjectStageProduc0on向けも同様

@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

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

ApacheDeltaspike@ConfigPropertyとProjectStage

•  2つに共通するメリット

•  環境変数やJavaシステムプロパティで振る舞いを変更

•  テスト済warを『修正なし』で複数環境で動作させる

開発環境 ステージング環境 商用環境

APServer

DB

myapp.war

Simurator

myapp.war myapp.war

関連システム

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

本日のコンテンツ

•  駆け足で振り返るCDI

•  CDI2.0

•  CDI + α

•  後に

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

CDI2.0(JavaEE8/2017)•  CDI非同期イベント

•  仕様をサブセットに分割

•  JavaSESupport

•  JavaSE8Alignment

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

CDI2.0をもっと知るにはcdi-spec.org/JIRA/Weld3.0.0.Alpha

• ホームページ (CDIspecで検索)

•  hkp://www.cdi-spec.org

•  JIRA•  hkps://issues.jboss.org/projects/CDI

•  CDI2.0EarlyDraZReview1の参照実装•  Weld3.0.0.Alpha16hkp://weld.cdi-spec.org/news/2016/04/28/weld-300Alpha16/

•  WildFly10に組込み可能なpatchもリリース

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

後に

CDI2.0 ドラフト仕様は今すぐWildFly10で動きます

ぜひ触ってみてください!

OracleとJavaは、OracleCorpora0on及びその子会社、関連会社の米国及びその他の国における登録商標です。文中の社名、商品名等は各社の商標または登録商標である場合があります。