cdi2.0アップデート&クックブック #javadaytokyo #jdt2016_4c
TRANSCRIPT
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 + α
• 後に
CDIContextandDependencyInjec0on
2009/12CDI1.0-JavaEE6
2013/5CDI1.1-JavaEE7
2014/4CDI1.2(maintenancerelease)
2017/1CDI2.0-JavaEE8
CDIの目的
1.DI/AOPを中心とした疎結合コードの実現@Inject,@InterceptorBinding,@Decorator,Event2.コンテキストを持つオブジェクトのライフサイクル管理@RequestScoped,@SessionScoped,@Applica0onScoped...
3.EJBSessionBeanとJSF@ManagedBeanの統合
CDI実装製品
• Weld(参照実装)-jboss.org
• GlassFish,WildFly/JBossEAP,WebLogic
• OpenWebBeans-ApacheSoZwareFounda0on• WebSphere,ApacheTomEE
ContextandDependencyInjec0on:CDI管理Beanの定義
// ライフサイクル: デプロイ〜アンデプロイまで %public class Controller {%%%}%%%// ライフサイクル: ユーザセッションごとに生成、ログアウトで破棄 %public class ShoppingCart implements Cart {...}%%
ContextandDependencyInjec0on:ランタイム例外を引き起こすコンテキスト操作
public class Controller { %...% HttpSession session = request.getSession();%
session.setAttribute(“shoppingCart”,newShoppingCart());%% ....%%
Cart cart = (Cart)session.getAttribute(“shopingCart”);%
ContextandDependencyInjec0on: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
ContextandDependencyInjec0on:CDI管理Beanのスコープ
ContextandDependencyInjec0on:@Injectでタイプセーフに取得
@ApplicationScoped%public class Controller {% @Inject% Cart cart;%}%%%@SessionScoped%public class ShoppingCart implements Cart {...}%%
CDIコンテナがインスタンスをセット
ContextandDependencyInjec0on:@InterceptorBinding-タイプセーフなインターセプタ適用
Log target
// target%@ApplicationScope%public class OrderService {% public void submit(Order order) {..}%}%
// Log%@Interceptor%public class LogInterceptor {...}%
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 {}
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
CDI1.1の変更点 (JavaEE7)beans.xmlのオプション化
• beans.xmlなしでCDI有効化
• スコープを持つクラスはすべてCDI管理Bean @RequestScoped, @SessionScoped, @ApplicationScoped ...
• @Dependentスコープは明示的に付与が必要
// Java EE 7デフォルトでは@Dependent省略不可%@Dependent%public class DependentBean {...}%
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 {...}%}
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
CDI1.1の変更点 (JavaEE7)スコープ開始・終了イベント
@ApplicationScoped%public class MasterDataCache {% public void observer(% @Observes @Initialized(ApplicationScoped.class)% ServletContext context) {% // initilize code% }%}%
• スコープの開始・終了タイミングでイベント発火
• Applica0onScopedの場合@Startup代わりに使える
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
本日のコンテンツ
• 駆け足で振り返るCDI
• CDI2.0
• CDI + α
• 後に
CDI2.0(JavaEE8/2017)• CDI非同期イベント
• 仕様をサブセットに分割
• JavaSESupport
• JavaSE8Alignment
@ApplicationScoped%public class AlertService {% @Inject AlertRepository repo;% % @Transactinal% public void handleAlert(Alert alert) {% // 何らかのビジネスロジックを終えた後に ...% repo.persist(alert);% }%}
通常のメソッド呼び出し初はシンプルな機能
AlertService
AlertRepository
@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
@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
通常のメソッド呼び出し手続き型のデメリット
• 機能追加毎にクラス間依存性が増加• やがては蜘蛛の巣になる
• CDI管理Beanが持つ状態のロールバックが難しい
• 宣言的トランザクションがコミット失敗した場合、
トランザクション中に変更したBeanのステートをどう戻すか
• catch節で頑張れるが、長くなることも
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);% ...% %
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);% }%}
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);% }%}
イベントと同じ引数を持つ全てのオブザーバに通知
CDIイベントの振り返りイベントモデルの一般的な利点
AlertService
AlertRepository
EmailSender
AlertCache
CDIEvent
AlertService
AlertRepository
EmailSender
AlertCache
• プラグイン構造
• 既存に手を入れずにObserver追加で拡張
• 実行タイミング/場所の分離
• 非同期実行、別マシンでの実行が理論上は可能となる
CDIContainer
Subject@Observe
Observer#1@Observe
Observer#2
1.fire()
2.callback#1
3.callback#2
CDIContainer
Subject@Observe
Observer#1@Observe
Observer#2
1.fire()
thread
2.callback#1
3.callback#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.0EDR1ではObserver側スレッドはコンテナ実装依存Weld3.0.0.Alpha16の場合:Weld自体が持つスレッドプールを使用(max-size->CPUコア数)
CDI2.0非同期CDIイベントコンテナ管理スレッドの利用 (ConcurrencyU0li0esforJavaEE)
@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);% }%} %
CDIContainer
Subject@ObserveAsyncObserver#1
@ObserveAsyncObserver#2
fireAsync()
callback
callback
fireAsync()は即座にreturnし、各Observerは別スレッドで実行
RequestthreadEventthread
CDIContainer
Subject@ObserveAsyncObserver#1
@ObserveAsyncObserver#2
callback
callback
transac0on#1
transac0on#2
tx#3
トランザクション・コンテキストはオブザーバに引き継がれない
RequestthreadEventthread
callback
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(JavaEE7)
CDI2.0(JavaEE8)
プラグイン(型依存の分離)
非同期実行(実行タイミングの分離)
○ ○○
CDI2.0非同期CDIイベント@MDBとCDI非同期イベント
CDI1.2(JavaEE7)
CDI2.0(JavaEE8)
JMS
プラグイン(型依存の分離)
非同期実行(実行タイミングの分離)
メッセージ永続化
Observerの別マシン実行
○ ○○
○○○○
CDI1.2(JavaEE7)
CDI2.0(JavaEE8)
JMS
プラグイン(型依存の分離)
非同期実行(実行タイミングの分離)
メッセージ永続化
Observerの別マシン実行
CDI2.0非同期CDIイベント@MDBとCDI非同期イベント
○ ○○
○○○○
【JMSに付いてくる検討項目】XAするならクラッシュリカバリ手順は?
ポイズンメッセージ対策は?メッセージ永続化先は?ファイル orDB?
CDI2.0非同期CDIイベント@MDBとCDI非同期イベント
CDI1.2(JavaEE7)
CDI2.0(JavaEE8)
JMS
プラグイン(型依存の分離)
非同期実行(実行タイミングの分離)
メッセージ永続化
Observerの別マシン実行考えるべき
タスクの多さ
○ ○○
○○○○△
CDI2.0非同期CDIイベントCDI非同期イベントが適するケース
• 順序性,依存性のない処理の並列実行
• 例外時のCDI管理Bean状態ロールバック
• トランザクション中に変更したステートを元に戻す
• メッセージ永続化が不要
• 例:朝からリクエスト時点までの業務統計レポート生成
• 障害復旧後に永続メッセージから実行しても、既に陳腐化
CDI2.0#2
仕様をサブセットに分割
CDI2.0仕様をサブセットに分割CDILite軽量なサブセットの抽出
• CDIをJavaEE以外の世界で使ってもらいたい• Android,組込みデバイス
• 現状のCDI仕様はJavaEE環境を前提
• プロキシベースを前提としない軽量実装
• Annota0onProcessingによるコンパイル時依存性解決(Androidでよく使われるDaggerがモデル)
• 省メモリ、低CPU使用率の実現
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との連携
CDI2.0#3
JavaSESupport
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の取得
CDI2.0JavaSESupport“仕様”として含める背景
• JavaEE仕様間での整合性• JAX-RS,JPAは JavaSEでも利用可能な仕様設計
• Weld,OpenWebBeansで既に実装されていた
• 実装間で類似APIが複数存在するのはJavaEE思想に反する
CDI2.0#4
JavaSE8Alignment
CDI2.0JavaSE8AlignmentInterceptorBuilder:ラムダorメソッド参照によるインターセプタ
public class InterceptorBuilder {% // デプロイ時にCDIコンテナよりコールバック% void afterBeanDiscovery(@Observes AfterBeanDiscovery event) {% event.addInterceptor() // return InterceptorBuilder%
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相当
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% }%}%
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% }%}%
CDI2.0JavaSE8AlignmentInterceptorBuilder:ラムダorメソッド参照によるインターセプタ
event.addInterceptor()% ...% .addBinding(Log.INSTANCE);%
CDI2.0JavaSE8AlignmentInterceptorBuilder:ラムダorメソッド参照によるインターセプタ
event.addInterceptor()% ...% .addBinding(Log.INSTANCE);%
@Log%public void target() {...}
適用対象メソッドと繋ぐために、アノテーションの“インスタンス”を渡す必要がある
CDI2.0JavaSE8AlignmentInterceptorBuilder:ラムダorメソッド参照によるインターセプタ
event.addInterceptor()% ...% .addBinding(Log.INSTANCE);%%@Inherited%@InterceptorBinding%@Retention(RUNTIME)%@Target({METHOD, TYPE})%public @interface Log {}%
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クラスを継承してアノテーションの”インスタンス”を取得
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
CDI2.0JavaSE8AlignmentInterceptorBuilderのメリット
• 1クラスで複数のインターセプタ定義が可能• クラスが冗長に増えるのを防ぐ
• JavaEEの何でもアノテーション状態の改善
• Java5から:アノテーションをスキャンしてコンテナ機能を付与
• Java8から:ラムダを渡すとコンテナが機能付与
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リリース 予定
本日のコンテンツ
• 駆け足で振り返るCDI
• CDI2.0
• CDI + α
• 後に
DI/AOPが標準化され、非同期イベントが入るのはわかった。
でも、まだ Springより足りないのでは?
SpringFramework
@Autowired,@Aspect%
CDI(JavaEE)
@Inject,@InterceptorDI/AOP
プロパティ管理@Value,
@PropertySource%
Java起動引数によるプロファイル切替 @Profile
CDIは『材料』のみ提供して、自作が必要なユースケースも多い
SpringFramework
@Autowired,@Aspect%
CDI(JavaEE)
@Inject,@InterceptorDI/AOP
プロパティ管理@Value,
@PropertySource%@Producesによる要自作
Java起動引数によるプロファイル切替 @Profile @Alternativeによる要自作
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では?
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
“あったらいいな”は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
ApacheDeltaspike便利なCDI拡張ライブラリ
• CDIのPortableExten0onを活かしたライブラリ
• Seem3+MyFacesCODI+αを統合
• 2014/6:1.0.0リリース (2016/4現在1.6.1が 新)
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
デフォルトのプロパティファイル
ApacheDeltaspike#1@ConfigProperty任意のプロパティファイルの適用
@Dependent%public class MyAppFileConfig implements PropertyFileConfig {% @Override% public String getPropertyFileName() {% return "META-INF/application.properties";% }%% @Override% public boolean isOptional() {% return false;% }%}
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. プロパティファイル
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>
ApacheDeltaspike#2ProjectStage起動オプションで有効なBeanを切り替える
@ApplicationScoped%public class Repository {% @PersistenceContext(unitName = “h2 or PostgreSQL??”)% private EntityManager em;% ...%}
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; %}
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; %}
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
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
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
ApacheDeltaspike@ConfigPropertyとProjectStage
• 2つに共通するメリット
• 環境変数やJavaシステムプロパティで振る舞いを変更
• テスト済warを『修正なし』で複数環境で動作させる
開発環境 ステージング環境 商用環境
APServer
DB
myapp.war
Simurator
myapp.war myapp.war
関連システム
本日のコンテンツ
• 駆け足で振り返るCDI
• CDI2.0
• CDI + α
• 後に
CDI2.0(JavaEE8/2017)• CDI非同期イベント
• 仕様をサブセットに分割
• JavaSESupport
• JavaSE8Alignment
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もリリース
後に
CDI2.0 ドラフト仕様は今すぐWildFly10で動きます
ぜひ触ってみてください!
OracleとJavaは、OracleCorpora0on及びその子会社、関連会社の米国及びその他の国における登録商標です。文中の社名、商品名等は各社の商標または登録商標である場合があります。