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

Post on 10-Jun-2015

20.490 Views

Category:

Technology

5 Downloads

Preview:

Click to see full reader

DESCRIPTION

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

TRANSCRIPT

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

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

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

Copyright  ©  NTT  COMWARE  2013

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

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

(2009年リリース)

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

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

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

(Spring  Framework  2002~)

本日のテーマ  

Context  and  Dependency  InjecOon

本日のコンテンツ

•  Dependency Injection - DI の復習

•  CDIの機能紹介

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

•  EL式との連携

•  インターセプタ

•  CDIのコンフィグ beans.xml

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

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

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

依存性の注入

Context  and  Dependency  InjecOon

Context  and  Dependency  InjecOon

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

依存性の注入

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

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

ClassA  

依存先  クラス  

依存先  クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

new

new

new

new

new

DBMS

関連他システム

メールサーバ

Service

Service

REST  Endpoint

DAO/Repository

JAX-­‐WS  Client

Mail  Client

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

ClassA  

依存先  クラス  

依存先  クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

new

new

new

new

new

DBMS

関連他システム

メールサーバ

Service

Service

REST  Endpoint

DAO/Repository

JAX-­‐WS  Client

Mail  Client

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

ClassA  

依存先  クラス  

依存先  クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

new

new

new

new

new

DBMS

関連他システム

メールサーバ

Service

Service

REST  Endpoint

DAO/Repository

JAX-­‐WS  Client

Mail  Client

テスト 対象

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

ClassA  

依存先  クラス  

依存先  クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

new

new

new

new

new

DBMS

関連他システム

メールサーバ

Service

Service

REST  Endpoint

DAO/Repository

JAX-­‐WS  Client

Mail  Client

テスト 対象

ユニットテストに

必要なクラス

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

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

ユニットテストしない  

時間を消費

終的に

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

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

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

ClassA  

インタフェース  

インタフェース  

さらなる  依存先クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

call

call

new

new

new

DBMS

関連他システム

メールサーバ

Service

Service

REST  Endpoint

DAO/Repository

JAX-­‐WS  Client

Mail  Client

実装クラス  

実装クラス  

ここで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にアクセス

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

DIコンテナの出番  

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

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コンテナが型が合う実装クラスを  探してインスタンス注入する。

ClassA  

インタフェース  

インタフェース  

さらなる  依存先クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

call

call

new

new

DBMS

関連他システム

メールサーバ

Service

Service

REST  Endpoint

DAO/Repository

JAX-­‐WS  Client

Mail  Client

フェイク実装  

フェイク実装  

JUnitテストケース  

フィールドにセット

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

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

ClassA  

依存先  クラス  

依存先  クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

new

new

new

new

new

DBMS

関連他システム

メールサーバ

Service

Service

REST  Endpoint

DAO/Repository

JAX-­‐WS  Client

Mail  Client

テスト 対象

ユニットテストに

必要なクラス

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

ClassA  

インタフェース  

インタフェース  

さらなる  依存先クラス  

さらなる  依存先クラス  

さらなる  依存先クラス  

call

call

new

new

DBMS

関連他システム

メールサーバ

Service

Service

REST  Endpoint

DAO/Repository

JAX-­‐WS  Client

Mail  Client

フェイク実装  

フェイク実装  

JUnitテストケース  

フィールドにセット

テスト 対象

ユニットテストに

必要なクラス

DIの主なメリット

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

•  メールの送信  

•  他システムとの連携  

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

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

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

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

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

Java  EE  版 仕様です  

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サーバ

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ができた

CDIの代表的な機能  

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

-  静的な型解決 @Qualifiler  

-  動的な型解決 @Produces    

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

•  EL式との組み合わせ  

•  インターセプタ @InterceptorBinding  

•  コンフィグ beans.xml

CDIの代表的な機能  

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

-  静的な型解決 @Qualifiler  

-  動的な型解決 @Produces    

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

•  EL式との組み合わせ  

•  インターセプタ @InterceptorBinding  

•  コンフィグ beans.xml

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

       @Inject          private  Service  service;

例 :  Servlet  に @Inject  する  

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

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

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

       @Inject          private  Service  service;

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

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

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

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

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

?   <<interface>>  Service  

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

call

ServiceImpl  

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

•  Servlet  関連 @WebServlet      @WebFilter      @WebListener  

•  EJB  Session  Bean   :  @Stateless  など  

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

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

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

public class ServiceImpl implements Service { @Inject Repository repository;

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

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

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

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

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

public class ServiceImpl implements Service { @Inject Repository repository;

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

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

public class ServiceImpl implements Service { @Inject Repository repository;

public class RepositoryImpl implements Repository {…}

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

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

CDIに生成される側の条件    

REST  Endpoint  等  <<interface>>  Service  

call

ServiceImpl  

CDIに生成される側

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

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

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

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

CDIの代表的な機能  

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

-  静的な型解決 @Qualifiler  

-  動的な型解決 @Produces    

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

•  EL式との組み合わせ  

•  インターセプタ @InterceptorBinding  

•  コンフィグ beans.xml

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

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

B.  デプロイに失敗する  

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

<<interface>>  DAO  

OracleDAO  

PostgresDAO  

@Inject  private  DAO  dao;

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

実装クラスが複数ある

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

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

B.  デプロイに失敗する  

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

<<interface>>  DAO  

OracleDAO  

PostgresDAO  

@Inject  private  DAO  dao;

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

実装クラスが複数ある

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

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

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

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

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

@Inject  @Oracle  private  DAO  dao;

@Oracle  public  class  OracleDAO  …

@PostgreSQL  public  class  PostgresDAO  …

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

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

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

@Inject  @PostgreSQL  private  DAO  dao;

@Oracle  public  class  OracleDAO  …

@PostgreSQL  public  class  PostgresDAO  …

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

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

<<REST  Endpoint>>  ChargeResource  

@Path(“/charge”)

PaypalService  

で支払う

で支払う SquareService  

<<interface>>  ChargeService  

ユーザA

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

動的な型解決  :  @Produces

<<REST  Endpoint>>  ChargeResource  

@Path(“/charge”)  @Credit

PaypalService   SquareService  

<<interface>>  ChargeService  

<<Producer>>  PaymentStrategy  

@Credit  @Produces

return結果をInject

依存 依存

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

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

プロデューサのコード例

<<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;            …

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

<<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;            …

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

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

<<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;            …

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

<<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;            …

CDIの代表的な機能  

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

-  静的な型解決 @Qualifiler  

-  動的な型解決 @Produces    

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

•  EL式との組み合わせ  

•  インターセプタ @InterceptorBinding  

•  コンフィグ beans.xml

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

クライアント サーバ

request

response

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

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

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

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

クライアント サーバ

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

Login

Logout

@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

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

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

デプロイ時初期化  @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がお勧め。

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

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

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

Servlet  <<interface>>  Service  

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

call

ServiceImpl  

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

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)

CDIの代表的な機能  

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

-  静的な型解決 @Qualifiler  

-  動的な型解決 @Produces    

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

•  EL式との組み合わせ  

•  インターセプタ @InterceptorBinding  

•  コンフィグ beans.xml

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;          …

CDIの代表的な機能  

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

-  静的な型解決 @Qualifiler  

-  動的な型解決 @Produces    

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

•  EL式との組み合わせ  

•  インターセプタ @InterceptorBinding  

•  コンフィグ beans.xml

インターセプタとは  

Intercep

tor

Intercep

tor

注文受付クラス  

課金業務クラス  

発送業務クラス  

メソッド開始 完了

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

共通処理

代表的なインターセプタ  

•  ロギング  

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

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

共通処理

インターセプタの作り方  

@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を付与した自作アノテーションで実装と対象を関連付け

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

注文受付クラス  

課金業務クラス  

発送業務クラス  

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

トラ

ンザ

クシ

ョン

開始

セキ

ュリ

ティ

処理

ロギ

ング

処理

業務処理 1 2 3開始 終了

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

インターセプタとコンフィグ  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  {  

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

CDIの代表的な機能  

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

-  静的な型解決 @Qualifiler  

-  動的な型解決 @Produces    

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

•  EL式との組み合わせ  

•  インターセプタ @InterceptorBinding  

•  コンフィグ beans.xml

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  を付与する。

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

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

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で繋ぐ

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が出ても  業務ロジックコードは変えたくない  

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

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

テスト 対象

テストに必要

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アクセス

インジェクション

インジェクション

EJBとの使い分け

@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されたら自動的にロールバック

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構築には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構築 に使う

基幹システムで 使う

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

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

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

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

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

top related