jjug 11月ナイトセミナー cdiをはじめよう

79
CDIをはじめよう NTTコムウェア株式会社 上妻 宜人 (あげつま のりと) はてなブログ : n-agetsuma.hatenablog.com JJUG ナイト・セミナー Java EE 特集』 Copyright © NTT COMWARE 2013

Upload: norito-agetsuma

Post on 10-Jun-2015

20.490 views

Category:

Technology


5 download

DESCRIPTION

JJUG 11月ナイトセミナーの発表資料です。 DI使用時のインタフェース使用の要否については、はてなブログにて補足しています。 http://n-agetsuma.hatenablog.com/entry/2013/12/11/211017

TRANSCRIPT

Page 1: JJUG 11月ナイトセミナー CDIをはじめよう

CDIをはじめよう NTTコムウェア株式会社 上妻 宜人 (あげつま のりと)

はてなブログ : n-agetsuma.hatenablog.com

JJUG  ナイト・セミナー 『Java  EE  特集』

Copyright  ©  NTT  COMWARE  2013

Page 2: JJUG 11月ナイトセミナー CDIをはじめよう

Java EE 6 からついにEJBを使わない

DI/AOPコンテナ仕様が入りました

(2009年リリース)

少し前の話になりますが…

Page 3: JJUG 11月ナイトセミナー CDIをはじめよう

DI求めてSpringに行かれた方、帰ってきて!

ロッド・ジョンソン 氏 著  邦訳 :  実践J2EEシステムデザイン

(Spring  Framework  2002~)

Page 4: JJUG 11月ナイトセミナー CDIをはじめよう

本日のテーマ  

Page 5: JJUG 11月ナイトセミナー CDIをはじめよう

Context  and  Dependency  InjecOon

Page 6: JJUG 11月ナイトセミナー CDIをはじめよう

本日のコンテンツ

•  Dependency Injection - DI の復習

•  CDIの機能紹介

•  インジェクション と スコープ

•  EL式との連携

•  インターセプタ

•  CDIのコンフィグ beans.xml

•  CDIの使いどころ/EJBとの機能比較

•  CDIをもっと学ぶためには – 参考文献

Page 7: JJUG 11月ナイトセミナー CDIをはじめよう

コンテキスト (スコープ)を持った

依存性の注入

Context  and  Dependency  InjecOon

Page 8: JJUG 11月ナイトセミナー CDIをはじめよう

Context  and  Dependency  InjecOon

コンテキスト (スコープ)を持った

依存性の注入

Page 9: JJUG 11月ナイトセミナー CDIをはじめよう

Web3層構造で振り返る  Dependency  InjecOon  の復習  

Page 10: JJUG 11月ナイトセミナー CDIをはじめよう

Web3層構造とnewによる依存性の連続性

ClassA  

依存先  クラス  

依存先  クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

new

new

new

new

new

DBMS

関連他システム

メールサーバ

Service

Service

REST  Endpoint

DAO/Repository

JAX-­‐WS  Client

Mail  Client

Page 11: JJUG 11月ナイトセミナー CDIをはじめよう

Web3層構造とnewによる依存性の連続性

ClassA  

依存先  クラス  

依存先  クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

new

new

new

new

new

DBMS

関連他システム

メールサーバ

Service

Service

REST  Endpoint

DAO/Repository

JAX-­‐WS  Client

Mail  Client

Page 12: JJUG 11月ナイトセミナー CDIをはじめよう

テストしたいのはREST  Endpointだけの場合

ClassA  

依存先  クラス  

依存先  クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

new

new

new

new

new

DBMS

関連他システム

メールサーバ

Service

Service

REST  Endpoint

DAO/Repository

JAX-­‐WS  Client

Mail  Client

テスト 対象

Page 13: JJUG 11月ナイトセミナー CDIをはじめよう

依存性の連続で結局全部必要になる

ClassA  

依存先  クラス  

依存先  クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

new

new

new

new

new

DBMS

関連他システム

メールサーバ

Service

Service

REST  Endpoint

DAO/Repository

JAX-­‐WS  Client

Mail  Client

テスト 対象

ユニットテストに

必要なクラス

Page 14: JJUG 11月ナイトセミナー CDIをはじめよう

依存性でユニットテストしにくい

時間がないのでユニットテスト困難  

ユニットテストしない  

時間を消費

終的に

Page 15: JJUG 11月ナイトセミナー CDIをはじめよう

こうしてテストのない  レガシーコードが生まれ続ける。  

参考  :  翔泳社 レガシーコード改善ガイド

Page 16: JJUG 11月ナイトセミナー CDIをはじめよう

まずはインタフェースに依存を切り替えて

ClassA  

インタフェース  

インタフェース  

さらなる  依存先クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

call

call

new

new

new

DBMS

関連他システム

メールサーバ

Service

Service

REST  Endpoint

DAO/Repository

JAX-­‐WS  Client

Mail  Client

実装クラス  

実装クラス  

Page 17: JJUG 11月ナイトセミナー CDIをはじめよう

ここでnewしてしまうと効果があまりない

ClassA  

インタフェース  

インタフェース  

さらなる  依存先クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

call

call

new

new

new

DBMS

関連他システム

メールサーバ

Service

Service

REST  Endpoint

DAO/Repository

JAX-­‐WS  Client

Mail  Client

実装クラス  

実装クラス  

public class ServiceImpl implements Service { … @Override public void doBusiness() { dao.select(); } } @Path (“/sample”) public class SampleResource {

public Entity sampleMethod () { Service service = new ServiceImpl(); service.doBusiness(); …

自分でローカル変数にnewすると  ユニットテスト時にDBにアクセス  してしまう。

実装クラスでDBにアクセス

Page 18: JJUG 11月ナイトセミナー CDIをはじめよう

誰かが実装クラスを探して、  自動でnewしてほしい  

DIコンテナの出番  

Page 19: JJUG 11月ナイトセミナー CDIをはじめよう

DIコンテナが実装クラスをnewして注入

ClassA  

インタフェース  

インタフェース  

さらなる  依存先クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

call

call

new

new

DBMS

関連他システム

メールサーバ

Service

Service

REST  Endpoint

DAO/Repository

JAX-­‐WS  Client

Mail  Client

実装クラス  

実装クラス  

DIコンテナ  (Spring,  Seaser2,  Guice,  CDI)  

Inject

Page 20: JJUG 11月ナイトセミナー CDIをはじめよう

DIコンテナが実装クラスをnewして注入

ClassA  

インタフェース  

インタフェース  

さらなる  依存先クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

call

call

new

new

DBMS

関連他システム

メールサーバ

Service

Service

REST  Endpoint

DAO/Repository

JAX-­‐WS  Client

Mail  Client

実装クラス  

実装クラス  

DIコンテナ  (Spring,  Seaser2,  Guice,  CDI)  

Inject

@Path (“/sample”) public class SampleResource {

@Inject Service service;

public Entity sampleMethod () { service.doBusiness(); ..

DIコンテナが型が合う実装クラスを  探してインスタンス注入する。

Page 21: JJUG 11月ナイトセミナー CDIをはじめよう

ClassA  

インタフェース  

インタフェース  

さらなる  依存先クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

call

call

new

new

DBMS

関連他システム

メールサーバ

Service

Service

REST  Endpoint

DAO/Repository

JAX-­‐WS  Client

Mail  Client

フェイク実装  

フェイク実装  

JUnitテストケース  

フィールドにセット

テスト時はフェイクに差替て、依存を断ち切る

Page 22: JJUG 11月ナイトセミナー CDIをはじめよう

再掲 :  各クラスを new  で繋いだ場合

ClassA  

依存先  クラス  

依存先  クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

new

new

new

new

new

DBMS

関連他システム

メールサーバ

Service

Service

REST  Endpoint

DAO/Repository

JAX-­‐WS  Client

Mail  Client

テスト 対象

ユニットテストに

必要なクラス

Page 23: JJUG 11月ナイトセミナー CDIをはじめよう

結果UTもしやすく、クラス間の依存も下がる

ClassA  

インタフェース  

インタフェース  

さらなる  依存先クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

call

call

new

new

DBMS

関連他システム

メールサーバ

Service

Service

REST  Endpoint

DAO/Repository

JAX-­‐WS  Client

Mail  Client

フェイク実装  

フェイク実装  

JUnitテストケース  

フィールドにセット

テスト 対象

ユニットテストに

必要なクラス

Page 24: JJUG 11月ナイトセミナー CDIをはじめよう

DIの主なメリット

•  特にユニットテストしにくい外部リソースへの依存に効果的  •  データベースへのアクセス  

•  メールの送信  

•  他システムとの連携  

•  インタフェースの切り出しとDIをセットで使う  

•  インタフェースに依存させて実装を差し替えやすくする  

•  結果的に依存の連鎖を止めることができる  

各クラス間の依存性を弱めることができる

Page 25: JJUG 11月ナイトセミナー CDIをはじめよう

CDIはここまで説明したDIコンテナの  

Java  EE  版 仕様です  

Page 26: JJUG 11月ナイトセミナー CDIをはじめよう

CDIについて

Page 27: JJUG 11月ナイトセミナー CDIをはじめよう

Context And Dependency Injection(コンテキストと依存性の注入)

•  Java EE 6 から CDI1.0 導入

•  Java EE 7 で CDI1.1 として小規模なアップデート

•  DIを使って、クラス間を依存性を少なく連携させる為の仕様

JBoss AS 7 CDI1.0 準拠

GlassFish 4.0 CDI1.1 準拠

WildFly8 CDI1.1 準拠予定

Tomee 1.x CDI1.0 準拠

CDIが使えるオープンソースAPサーバ

Page 28: JJUG 11月ナイトセミナー CDIをはじめよう

Java  EE  仕様の中でのCDI位置づけ

Web 層 ビジネス 層 永続化層

CDI (3層をDIコンテナで繋ぐ)

EJB

JAX-RS

WebSocket

JPA

Client EIS

PCブラウザ

モバイル

RDBMS 等

Java EE 7 Specifications

JSF

CDI EJBを使わない

ビジネスロジックの実現

•  DI機能によって各層間の依存性を解決する

•  EJB を使わないビジネスロジックの実現

→ Java EE 5 まではEJBのみDIができた

Page 29: JJUG 11月ナイトセミナー CDIをはじめよう

CDIの代表的な機能  

•  実装インスタンスのインジェクション @Inject  

-  静的な型解決 @Qualifiler  

-  動的な型解決 @Produces    

•  スコープ @RequestScoped,  @SessionScoped  など  

•  EL式との組み合わせ  

•  インターセプタ @InterceptorBinding  

•  コンフィグ beans.xml

Page 30: JJUG 11月ナイトセミナー CDIをはじめよう

CDIの代表的な機能  

•  実装インスタンスのインジェクション @Inject  

-  静的な型解決 @Qualifiler  

-  動的な型解決 @Produces    

•  スコープ @RequestScoped,  @SessionScoped  など  

•  EL式との組み合わせ  

•  インターセプタ @InterceptorBinding  

•  コンフィグ beans.xml

Page 31: JJUG 11月ナイトセミナー CDIをはじめよう

@WebServlet(“/sample”)  public  class  SampleServlet  extends  HcpServlet  {  

       @Inject          private  Service  service;

例 :  Servlet  に @Inject  する  

APサーバが自動的にServiceインタフェースの  実装クラスを探してnewして注入

Page 32: JJUG 11月ナイトセミナー CDIをはじめよう

例 :  RESTエンドポイントに @Inject  する  

@Path(“/sample”)  public  class  SampleResource    {  

       @Inject          private  Service  service;

APサーバが自動的にServiceインタフェースの  実装クラスを探してnewして注入

Page 33: JJUG 11月ナイトセミナー CDIをはじめよう

例 :  EJBも@Injectでインジェクション可能  

@Path(“/sample”)  public  class  SampleResource    {  //  @EJB          @Inject          private  SampleSessionBean  service;

APサーバが自動的に  SessionBean実装を探して注入

Page 34: JJUG 11月ナイトセミナー CDIをはじめよう

インジェクションされる側の条件    

?   <<interface>>  Service  

インジェクションされる側  (@Injectを書く方)

call

ServiceImpl  

条件 :  コンテナ管理Bean  (newしてないインスタンス)  であること    

•  Servlet  関連 @WebServlet      @WebFilter      @WebListener  

•  EJB  Session  Bean   :  @Stateless  など  

•  JAX-­‐RS  RESTエンドポイント :  @Path  など  

•  CDIによって生成されたインスタンス  

Page 35: JJUG 11月ナイトセミナー CDIをはじめよう

@Path(“/test”) public class SampleResource { @Inject Service service;

public class ServiceImpl implements Service { @Inject Repository repository;

CDIによって生成されたインスタンスには注入可能

実装クラスServiceImplの  インスタンスをインジェクション

Page 36: JJUG 11月ナイトセミナー CDIをはじめよう

CDIによって生成されたインスタンスには注入可能

CDIによって  インスタンス生成

@Path(“/test”) public class SampleResource { @Inject Service service;

public class ServiceImpl implements Service { @Inject Repository repository;

Page 37: JJUG 11月ナイトセミナー CDIをはじめよう

CDIによって生成されたインスタンスには注入可能

@Path(“/test”) public class SampleResource { @Inject Service service;

public class ServiceImpl implements Service { @Inject Repository repository;

public class RepositoryImpl implements Repository {…}

さらなるインジェクションが可能

CDIによって  インスタンス生成

Page 38: JJUG 11月ナイトセミナー CDIをはじめよう

CDIに生成される側の条件    

REST  Endpoint  等  <<interface>>  Service  

call

ServiceImpl  

CDIに生成される側

•  引数なしコンストラクタを含むクラス  

•  インタフェースの実装はなくても @Inject  でインジェクション可能  

•  アノテーションもいらない完全なPOJO  (Plain  Old  Java  Object)  

引数なしコンストラクタがあれば、どんなクラスも注入可能

Page 39: JJUG 11月ナイトセミナー CDIをはじめよう

CDIの代表的な機能  

•  実装インスタンスのインジェクション @Inject  

-  静的な型解決 @Qualifiler  

-  動的な型解決 @Produces    

•  スコープ @RequestScoped,  @SessionScoped  など  

•  EL式との組み合わせ  

•  インターセプタ @InterceptorBinding  

•  コンフィグ beans.xml

Page 40: JJUG 11月ナイトセミナー CDIをはじめよう

インタフェースの実装が複数ある場合は?  

A.  インジェクションフィールドがnullのまま  

B.  デプロイに失敗する  

C.  初にロードしたクラスをインジェクション

<<interface>>  DAO  

OracleDAO  

PostgresDAO  

@Inject  private  DAO  dao;

インジェクション先コード

実装クラスが複数ある

Page 41: JJUG 11月ナイトセミナー CDIをはじめよう

インタフェースの実装が複数ある場合は?  

A.  インジェクションフィールドがnullのまま  

B.  デプロイに失敗する  

C.  初にロードしたクラスをインジェクション

<<interface>>  DAO  

OracleDAO  

PostgresDAO  

@Inject  private  DAO  dao;

インジェクション先コード

実装クラスが複数ある

Page 42: JJUG 11月ナイトセミナー CDIをはじめよう

静的な型解決  :  Qualifier  (修飾子) の使用

1.  @Qualifier  が付与されたアノテーションを作成

@Qualifier  @RetenOon  (RunOme)  @Target  ({METHOD,  FIELD,  PARAMETER,  TYPE})  public  @interface  Oracle  {}  

Page 43: JJUG 11月ナイトセミナー CDIをはじめよう

静的な型解決  :  Qualifier  (修飾子) の使用

2.  インジェクション先とBean両方に付与する

@Inject  @Oracle  private  DAO  dao;

@Oracle  public  class  OracleDAO  …

@PostgreSQL  public  class  PostgresDAO  …

OracleDAOをインジェクションしたい場合は@Injectと@Oracleを指定

Page 44: JJUG 11月ナイトセミナー CDIをはじめよう

静的な型解決  :  Qualifier  (修飾子) の使用

3.  インジェクション対象を変更したい場合

@Inject  @PostgreSQL  private  DAO  dao;

@Oracle  public  class  OracleDAO  …

@PostgreSQL  public  class  PostgresDAO  …

PostgresDAOをインジェクションしたい場合は修飾子を書き換える。

Page 45: JJUG 11月ナイトセミナー CDIをはじめよう

実行時に実装型の解決をしたい場合

<<REST  Endpoint>>  ChargeResource  

@Path(“/charge”)

PaypalService  

で支払う

で支払う SquareService  

<<interface>>  ChargeService  

ユーザA

ユーザB ユーザに応じて実装を変えたい

Page 46: JJUG 11月ナイトセミナー CDIをはじめよう

動的な型解決  :  @Produces

<<REST  Endpoint>>  ChargeResource  

@Path(“/charge”)  @Credit

PaypalService   SquareService  

<<interface>>  ChargeService  

<<Producer>>  PaymentStrategy  

@Credit  @Produces

return結果をInject

依存 依存

@Produces  メソッドと限定子を併用して動的な型の解決を行う

インジェクションする型の  判断ロジックを実装

Page 47: JJUG 11月ナイトセミナー CDIをはじめよう

プロデューサのコード例

<<REST  Endpoint>>  ChargeResource  

@Path(“/charge”)

PaypalService   SquareService  

<<interface>>  ChargeService  

<<Producer>>  PaymentStrateg

y  

@Produces

return結果をInject

依存 依存

@RequestScoped  public  class  PaymentStrategy  {  

       private  PaymentType  paymentType;  

     @Credit  @Produces          public  ChargeService  getStrategy(PaypalService  paypal,  SqureService  square)  {                  switch  (paymentType)  {                          case  PayPal  :  return  paypal;                          case  Square  :  return  square;                  }  

       }  

       …

@Path  (“/charge”)  public  class  ChargeResource  {          @Inject  @Credit            ChargeService  service;            …

Page 48: JJUG 11月ナイトセミナー CDIをはじめよう

プロデューサメソッドのコード例

<<REST  Endpoint>>  ChargeResource  

@Path(“/charge”)

PaypalService   SquareService  

<<interface>>  ChargeService  

<<Producer>>  PaymentStrateg

y  

@Produces

return結果をInject

依存 依存

@RequestScoped  public  class  PaymentStrategy  {  

       private  PaymentType  paymentType;  

     @Credit  @Produces          public  ChargeService  getStrategy(PaypalService  paypal,  SqureService  square)  {                  switch  (paymentType)  {                          case  PayPal  :  return  paypal;                          case  Square  :  return  square;                  }  

       }  

       …

返り値型(ChargeService)と  限定子(@Credit)で括り付けられる。

@Path  (“/charge”)  public  class  ChargeResource  {          @Inject  @Credit            ChargeService  service;            …

限定子を忘れると、型が不定となるデプロイエラーが発生するので注意

Page 49: JJUG 11月ナイトセミナー CDIをはじめよう

プロデューサメソッドのコード例

<<REST  Endpoint>>  ChargeResource  

@Path(“/charge”)

PaypalService   SquareService  

<<interface>>  ChargeService  

<<Producer>>  PaymentStrateg

y  

@Produces

return結果をInject

依存 依存

@RequestScoped  public  class  PaymentStrategy  {  

       private  PaymentType  paymentType;  

     @Credit  @Produces          public  ChargeService  getStrategy(PaypalService  paypal,  SqureService  square)  {                  switch  (paymentType)  {                          case  PayPal  :  return  paypal;                          case  Square  :  return  square;                  }  

       }  

       …

実装インスタンスはメソッド引数に  APサーバから渡される  

@Path  (“/charge”)  public  class  ChargeResource  {          @Inject  @Credit            ChargeService  service;            …

Page 50: JJUG 11月ナイトセミナー CDIをはじめよう

プロデューサメソッドのコード例

<<REST  Endpoint>>  ChargeResource  

@Path(“/charge”)

PaypalService   SquareService  

<<interface>>  ChargeService  

<<Producer>>  PaymentStrateg

y  

@Produces

return結果をInject

依存 依存

@RequestScoped  public  class  PaymentStrategy  {  

       private  PaymentType  paymentType;  

     @Credit  @Produces          public  ChargeService  getStrategy(PaypalService  paypal,  SqureService  square)  {                  switch  (paymentType)  {                          case  PayPal  :  return  paypal;                          case  Square  :  return  square;                  }  

       }  

       …

インジェクションしたい実装を  条件に応じてreturnする。  

@Path  (“/charge”)  public  class  ChargeResource  {          @Inject  @Credit            ChargeService  service;            …

Page 51: JJUG 11月ナイトセミナー CDIをはじめよう

CDIの代表的な機能  

•  実装インスタンスのインジェクション @Inject  

-  静的な型解決 @Qualifiler  

-  動的な型解決 @Produces    

•  スコープ @RequestScoped,  @SessionScoped  など  

•  EL式との組み合わせ  

•  インターセプタ @InterceptorBinding  

•  コンフィグ beans.xml

Page 52: JJUG 11月ナイトセミナー CDIをはじめよう

@RequestScoped  :  リクエスト受付~応答まで  

クライアント サーバ

request

response

リクエスト毎にインジェクションしなおす

@RequestScoped  public  class  SampleBean  {  …  }    @Path  (“/sample”)  public  class  SampleResource  {          @Inject  SampleBean  bean;  

Page 53: JJUG 11月ナイトセミナー CDIをはじめよう

@SessionScoped  public  class  User            implements  Serializable  {  …  }    @Model    //  JSF2.x  public  class  SampleController  {          @Inject  User  user;  

@SessionScoped  :  ログイン~ログアウト  

クライアント サーバ

同一セッション中は、状態が保持された  同じインスタンスがインジェクションされる  

Login

Logout

Page 54: JJUG 11月ナイトセミナー CDIをはじめよう

@ConversaOonScoped  :  Session未満の任意長さ  

クライアント サーバ

@Named  @ConversaOonScoped  public  class  ConversaOonController                      implements  Serializable  {            @Inject          private  ConversaOon  conversaOon;            public  void  begin()  {                  …                  conversaOon.begin();          }            public  void  end()  {                  …                  conversaOon.end();          }  

Begin

End

Login

Logout

Page 55: JJUG 11月ナイトセミナー CDIをはじめよう

アプリケーションスコープの使い分け  

生存期間   初期化から~  アンデプロイまで

デプロイ時初期化  @Startup  

ない  

同じ 同じ

@ApplicaOonScoped  (CDI)

@Singleton  (JSR-­‐330)

@Singleton  (EJB)

ある

ロック制御  @Lock   ない   ある

ない  @WebListnerと組合せが必要  

ない  左記に同じ  

シリアライズ対応  (クラスタ考慮?)   ある ない   仕様に言及なし  

•  アプリケーションスコープ @javax.enterprise.context.ApplicaOonScoped  

•  JSR-330のシングルトン @javax.inject.Singleton  

•  EJBのシングルトン @javax.ejb.Singleton  

似たような機能が複数ある

@Startupや@Lockが使いたい場合はEJBがお勧め。

Page 56: JJUG 11月ナイトセミナー CDIをはじめよう

@WebServlet(“/sample”)  public  class  SampleServlet  extends  HcpServlet  {  

       @Inject          private  Service  service;    //  デフォルトは @Dependent  であると暗黙的に判定  public  class  ServiceImpl  extends  Service  {…}

@Dependent  :  インジェクション先に合わせる (default)  

Servlet  <<interface>>  Service  

サーブレットは  シングルインスタンス  

call

ServiceImpl  

サーブレット生成時に  一度だけインジェクション  

Page 57: JJUG 11月ナイトセミナー CDIをはじめよう

CDIで使用可能なスコープ一覧  

•  リクエストスコープ @javax.enterprise.context.RequestScoped  

•  会話スコープ @javax.enterprise.context.ConversaOonScoped  

•  セッションスコープ @javax.enterprise.context.SessionScoped  

•  アプリケーションスコープ @javax.enterprise.context.ApplicaOonScoped  

短い

長い

•  依存先に応じる(デフォルト)      @javax.enterprise.context.Dependent  

•  シングルトン  @javax.inject.Singleton  

スコープ

擬似スコープ (pseudo  scope)

Page 58: JJUG 11月ナイトセミナー CDIをはじめよう

CDIの代表的な機能  

•  実装インスタンスのインジェクション @Inject  

-  静的な型解決 @Qualifiler  

-  動的な型解決 @Produces    

•  スコープ @RequestScoped,  @SessionScoped  など  

•  EL式との組み合わせ  

•  インターセプタ @InterceptorBinding  

•  コンフィグ beans.xml

Page 59: JJUG 11月ナイトセミナー CDIをはじめよう

JSF  2.x  /  CDI  :  @NamedによるELバインディング  

<h:inputSecret value=“#{password.now} “ ..

@Named  @RequestScope  public  class  Password  {          private  String  now;          …

@Named  @RequestScope  public  class  PassController  {          @Inject          private  Password  password;          …

Page 60: JJUG 11月ナイトセミナー CDIをはじめよう

CDIの代表的な機能  

•  実装インスタンスのインジェクション @Inject  

-  静的な型解決 @Qualifiler  

-  動的な型解決 @Produces    

•  スコープ @RequestScoped,  @SessionScoped  など  

•  EL式との組み合わせ  

•  インターセプタ @InterceptorBinding  

•  コンフィグ beans.xml

Page 61: JJUG 11月ナイトセミナー CDIをはじめよう

インターセプタとは  

Intercep

tor

Intercep

tor

注文受付クラス  

課金業務クラス  

発送業務クラス  

メソッド開始 完了

メソッドの開始・終了に割込み,業務とは直接関連ないシステム処理を実行

共通処理

代表的なインターセプタ  

•  ロギング  

•  セキュリティ関連 (認証や認可処理)  

•  トランザクションの開始、コミット、ロールバック制御  

共通処理

Page 62: JJUG 11月ナイトセミナー CDIをはじめよう

インターセプタの作り方  

@InterceptorBinding  @Target  ({Method,  TYPE})  @RetenOon(RunOme)  public  @interface  Logging  {}  

1.  アノテーション作る 2.  インターセプタ実装を作る

@Logging  @Interceptor  public  class  LoggingInterceptor  {      …      @AroundInvoke      public  void  log(InvocaOonContext  ic)  {              logger.debug(“log  message”);              return  ic.proceed();      }

@Logging  public  void  charge(int  amount)  {…}  

3.  インターセプタ対象にバインドさせる

@InterceptorBindingを付与した自作アノテーションで実装と対象を関連付け

Page 63: JJUG 11月ナイトセミナー CDIをはじめよう

インターセプタの優先順位は?  

注文受付クラス  

課金業務クラス  

発送業務クラス  

インターセプタ順序を定義したい

トラ

ンザ

クシ

ョン

開始

セキ

ュリ

ティ

処理

ロギ

ング

処理

業務処理 1 2 3開始 終了

インターセプタの順序が重要な場合も多くある。

Page 64: JJUG 11月ナイトセミナー CDIをはじめよう

インターセプタとコンフィグ  Java  EE  6  ではXMLが必須、 EE  7  では @Priority  が導入

•  Java  EE  6  の場合 :  WEB-­‐INF/beans.xml  に設定 (1つしかなくても必須)

<beans>          <interceptors>                  <class>interceptor.LoggingInterceptor</class>                  <class>intreceptor.SampleIntreceptor</class>          </interceptors>  </beans>

先に実行される

後に実行される

•  Java  EE  7  の場合 :  XMLなしで、@Priority  で代用が可能

@Logging  @Interceptor  @Dependent  @Priority(ApplicaOon+10)  public  class  LoggingInterceptor  {  

@Sample  @Interceptor  @Dependent  @Priority(ApplicaOon+20)  public  class  SampleInterceptor  {  

先に実行される 後に実行される

Page 65: JJUG 11月ナイトセミナー CDIをはじめよう

CDIの代表的な機能  

•  実装インスタンスのインジェクション @Inject  

-  静的な型解決 @Qualifiler  

-  動的な型解決 @Produces    

•  スコープ @RequestScoped,  @SessionScoped  など  

•  EL式との組み合わせ  

•  インターセプタ @InterceptorBinding  

•  コンフィグ beans.xml

Page 66: JJUG 11月ナイトセミナー CDIをはじめよう

beans.xmlの配置  

•  Java  EE  6  の場合 :  WEB-­‐INF/beans.xml  を含めるとCDIが有効化

Java  EE  6  ではbeans.xmlが必須、EE  7  からはオプション化

•  Java  EE  7  の場合 :  beans.xmlなしで有効化されるが、スコープ指定が必須

@Dependent public class ServiceImpl implements .. {

インジェクション先のスコープと同じにする場合でも、  省略せずに明示的に @Dependent  を付与する。

インターセプタがない場合は、  中身は空ファイルで良い。

Page 67: JJUG 11月ナイトセミナー CDIをはじめよう

CDIを Java  EE  アプリでどう使うか

Page 68: JJUG 11月ナイトセミナー CDIをはじめよう

REST  Endpoint  (JAX-­‐RS2.x)  

Service  (CDI  Bean)  

Repository  (JPA2.x)  

RDBMS BackingBean  (JSF2.x)  

WebSocket  

Web 層 ビジネス 層 永続化層

RDBMS以外の  永続化機構  (KVSなど)

クライアント

Java EE の 3層アーキテクチャ

Servlet  

技術の変化が激しい部分は、ロジックとは別層 (クラス)に切り出す

3層モデルの依存性をDIで繋ぐ

Page 69: JJUG 11月ナイトセミナー CDIをはじめよう

3層モデルの依存性をDIで繋ぐ

REST  Endpoint  (JAX-­‐RS2.x)  

Service  (CDI  Bean)  

Repository  (JPA2.x)  

RDBMS BackingBean  (JSF2.x)  

WebSocket  

Web 層 ビジネス 層 永続化層

RDBMS以外の  永続化機構  (KVSなど)

クライアント

Java EE の 3層アーキテクチャ

Servlet  

ビジネスロジックは特定技術に依存したくない

業務例 :    ・ 電話設備の登録/削除を行う  ・ 支払いがなければ督促する  

WebSocketが出ても、KVSが出ても  業務ロジックコードは変えたくない  

Page 70: JJUG 11月ナイトセミナー CDIをはじめよう

3層モデルの依存性をDIで繋ぐ

REST  Endpoint  (JAX-­‐RS2.x)  

Repository  (JPA2.x)  

RDBMS BackingBean  (JSF2.x)  

WebSocket  

Web 層 ビジネス 層 永続化層

RDBMS以外の  永続化機構  (KVSなど)

クライアント

Java EE の 3層アーキテクチャ

Servlet  

シンプルに new  で繋いでいくと …    

Service  (CDI  Bean)  

new new

new

Page 71: JJUG 11月ナイトセミナー CDIをはじめよう

3層モデルの依存性をDIで繋ぐ

REST  Endpoint  (JAX-­‐RS2.x)  

Repository  (JPA2.x)  

RDBMS BackingBean  (JSF2.x)  

WebSocket  

Web 層 ビジネス 層 永続化層

RDBMS以外の  永続化機構  (KVSなど)

クライアント

Java EE の 3層アーキテクチャ

Servlet  

冒頭の通り依存性が強くテストできない等 の課題

Service  (CDI  Bean)  

new new

new

テスト 対象

テストに必要

Page 72: JJUG 11月ナイトセミナー CDIをはじめよう

3層モデルの依存性をDIで繋ぐ

REST  Endpoint  (JAX-­‐RS2.x)  

Service  (CDI  Bean)  

Repository  (JPA2.x)  

RDBMS

Web 層 ビジネス 層 永続化層

クライアント

Java EE の 3層アーキテクチャ

@Injectでユニットテストしやすく、依存性を少なく。

@Path(“/sample”)  public  class  Resource  {  

   @Inject      private  Service  service;  

public  class  Service  {  

   @Inject      private  Repository  …  

public  class  Repository  {  

   @PersistenceContext      private  EnOtyManager  ..  

REST処理 業務処理 DBアクセス

インジェクション

インジェクション

Page 73: JJUG 11月ナイトセミナー CDIをはじめよう

EJBとの使い分け

Page 74: JJUG 11月ナイトセミナー CDIをはじめよう

@Transactional の導入 (Java EE 7)

EJBの宣言的トランザクションがCDIでもできるようになった

public  class  BankService  {          …          //  口座振り替えメソッド          @TransacOonal(TransacOonal.TxType.REQUIRED)          public  void  transfer(int  amount)  {                  pay(amount);                    //  振り込み元から出金                  receipt(amount);        //  振込み先に入金          }

•  Spring  の@TransacOonalと同じように使える  

•  RunOmeExcepOonがthrowされたら自動的にロールバック

Page 75: JJUG 11月ナイトセミナー CDIをはじめよう

CDIとEJBの機能の比較

DI/AOP  

CDI1.1 EJB3.1

EL式連携  

ある  (@Inject  等)

ある  (@Inject,  @EJB  等)

ない  ある  

(@Named)

ある  (@RequestScoped  等) スコープ   ない  

(@Stateless  or  @Stateful)  

宣言的  トランザクション  

ある  (@Stateless  or  @Stateful)  

ある  (@TransacOonal)

非同期実行   ある  (@Asynchronous)  

ない  

MQ連携   ある  (@MDB)  

ない  

リモート実行   ある  (@Remote)  

ない  

タイマ機能   ある  (@Schedule)  

ない  

Page 76: JJUG 11月ナイトセミナー CDIをはじめよう

Web構築にはCDIで十分、基幹機能はEJB継続使用

DI/AOP  

CDI1.1 EJB3.1

EL式連携  

ある  (@Inject  等)

ある  (@Inject,  @EJB  等)

ない  ある  

(@Named)

ある  (@RequestScoped  等) スコープ   ない  

(@Stateless  or  @Stateful)  

宣言的  トランザクション  

ある  (@Stateless  or  @Stateful)  

ある  (@TransacOonal)

非同期実行   ある  (@Asynchronous)  

ない  

MQ連携   ある  (@MDB)  

ない  

リモート実行   ある  (@Remote)  

ない  

タイマ機能   ある  (@Schedule)  

ない  

Web構築 に使う

基幹システムで 使う

Page 77: JJUG 11月ナイトセミナー CDIをはじめよう

CDIをより深く学ぶためには

Page 78: JJUG 11月ナイトセミナー CDIをはじめよう

CDIのマニュアル・ドキュメント 等

•  Weldのドキュメント (CDI参照実装)  •  hcp://docs.jboss.org/weld/reference/2.0.3.Final/en-­‐US/  

•  Java  EE  7  Turial  -­‐  PartⅤ  Context  and  Dependency  InjecOon  for  Java  EE  

•  hcp://docs.oracle.com/javaee/7/tutorial/doc/partcdi.htm  

•  CDI  1.1  仕様書  

•  hcp://jcp.org/en/jsr/detail?id=346  

•  書籍 :  O’Reilly  Java  EE  7  EssenOals  

•  hcp://shop.oreilly.com/product/0636920030614.do  

•  書籍 :  Apress  Beginning  Java  EE  7  

•  hcp://www.apress.com/9781430246268

©  O’Reilly  Media,  Inc.  

©  Apress  Media  LLC

Page 79: JJUG 11月ナイトセミナー CDIをはじめよう

GlassFish4  を今すぐダウンロードして是非試してみてください!  

ご清聴ありがとうございました。

hcps://glassfish.java.net/download.html

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