SlideShare a Scribd company logo
JJUG	
  ナイト・セミナー 『Java	
  EE	
  特集』	

CDIをはじめよう	
NTTコムウェア株式会社 上妻 宜人 (あげつま のりと)	
はてなブログ : n-agetsuma.hatenablog.com	

Copyright	
  ©	
  NTT	
  COMWARE	
  2013
少し前の話になりますが…	

Java EE

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

(2009年リリース)	

DI/AOPコンテナ仕様が入りました
DI求めてSpringに行かれた方、帰ってきて!	

(Spring	
  Framework	
  2002~)	

ロッド・ジョンソン 氏 著	
  
邦訳 :	
  実践J2EEシステムデザイン
本日のテーマ	
  
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による依存性の連続性	
DAO/Repository	
Service	
REST	
  
Endpoint	

new	

new	

さらなる	
  
依存先クラス	
  

依存先	
  
クラス	
  

DBMS	

ClassA	
  

JAX-­‐WS	
  Client	
new	

Service	

new	

依存先	
  
クラス	
  

さらなる	
  
依存先クラス	
  

Mail	
  Client	
new	

関連他システム	

さらなる	
  
依存先クラス	
  

メールサーバ
Web3層構造とnewによる依存性の連続性	
DAO/Repository	
Service	
REST	
  
Endpoint	

new	

new	

さらなる	
  
依存先クラス	
  

依存先	
  
クラス	
  

DBMS	

ClassA	
  

JAX-­‐WS	
  Client	
new	

Service	

new	

依存先	
  
クラス	
  

さらなる	
  
依存先クラス	
  

Mail	
  Client	
new	

関連他システム	

さらなる	
  
依存先クラス	
  

メールサーバ
テストしたいのはREST	
  Endpointだけの場合	
DAO/Repository	
Service	
REST	
  
Endpoint	

new	

テスト	
対象	

new	

依存先	
  
クラス	
  

DBMS	

ClassA	
  

new	

さらなる	
  
依存先クラス	
  

JAX-­‐WS	
  Client	
Service	

new	

依存先	
  
クラス	
  

さらなる	
  
依存先クラス	
  

Mail	
  Client	
new	

関連他システム	

さらなる	
  
依存先クラス	
  

メールサーバ
依存性の連続で結局全部必要になる	
DAO/Repository	
Service	
REST	
  
Endpoint	

new	

テスト	
対象	
ClassA	
  

new	

new	

さらなる	
  
依存先クラス	
  

依存先	
  
クラス	
  

DBMS	

ユニットテストに	
JAX-­‐WS	
  Client	
Service	
依存先	
  
クラス	
  

必要なクラス	
new	

さらなる	
  
依存先クラス	
  

Mail	
  Client	
new	

関連他システム	

さらなる	
  
依存先クラス	
  

メールサーバ
依存性でユニットテストしにくい	
時間を消費	

時間がないのでユニットテスト困難	
  
最終的に	

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

参考	
  :	
  翔泳社 レガシーコード改善ガイド
まずはインタフェースに依存を切り替えて	
DAO/Repository	
Service	
インタフェース	
  

REST	
  
Endpoint	

new	

さらなる	
  
依存先クラス	
  

DBMS	

call	
実装クラス	
  

ClassA	
  

JAX-­‐WS	
  Client	
call	

Service	
インタフェース	
  

new	

さらなる	
  
依存先クラス	
  

Mail	
  Client	
実装クラス	
  

new	

関連他システム	

さらなる	
  
依存先クラス	
  

メールサーバ
ここでnewしてしまうと効果があまりない	
public class ServiceImpl implements Service {
DAO/Repository	
…
さらなる	
  
Service	
@Override public void doBusiness() 依存先クラス	
  
{
new	
インタフェース	
  
dao.select();
REST	
  
call	
} Endpoint	
実装クラスでDBにアクセス	
実装クラス	
  
}

DBMS	

ClassA	
  

JAX-­‐WS	
  Client	
自分でローカル変数にnewすると	
  
@Path (“/sample”) Service	
ユニットテスト時にDBにアクセス	
  
さらなる	
  
call	
してしまう。	
public class SampleResource { new	
 依存先クラス	
  
インタフェース	
  

public Entity sampleMethod () { Mail	
  Client	
さらなる	
  
Service service =実装クラス	
   new	
 依存先クラス	
  
new ServiceImpl();
service.doBusiness();
…

関連他システム	

メールサーバ
誰かが実装クラスを探して、	
  
自動でnewしてほしい	
  

DIコンテナの出番	
  
DIコンテナが実装クラスをnewして注入	
DAO/Repository	
さらなる	
  
依存先クラス	
  

Service	
インタフェース	
  

REST	
  
Endpoint	

DBMS	

call	
実装クラス	
  

ClassA	
  

new	
JAX-­‐WS	
  Client	

call	

Service	
インタフェース	
  

さらなる	
  
依存先クラス	
  

Mail	
  Client	

Inject	
実装クラス	
  

関連他システム	

さらなる	
  
依存先クラス	
  

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

メールサーバ
DIコンテナが実装クラスをnewして注入	
DAO/Repository	
Service	

さらなる	
  
DIコンテナが型が合う実装クラスを	
  
依存先クラス	
  

@Path (“/sample”) インタフェース	
   探してインスタンス注入する。	
public class SampleResource {
REST	
  
DBMS	
call	
Endpoint	

実装クラス	
  
@Inject Service service;
ClassA	
  

new	

public Entity sampleMethod () {
Service	
call	
インタフェース	
  
service.doBusiness();
.. Inject	
実装クラス	
  

JAX-­‐WS	
  Client	
さらなる	
  
依存先クラス	
  

Mail	
  Client	

関連他システム	

さらなる	
  
依存先クラス	
  

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

メールサーバ
テスト時はフェイクに差替て、依存を断ち切る	
DAO/Repository	
さらなる	
  
依存先クラス	
  

Service	
インタフェース	
  

REST	
  
Endpoint	

フェイク実装	
  

ClassA	
  

new	
JAX-­‐WS	
  Client	

call	
フィールド
にセット	

DBMS	

call	

Service	
インタフェース	
  

さらなる	
  
依存先クラス	
  

Mail	
  Client	
フェイク実装	
  

new	
JUnitテストケース	
  

関連他システム	

さらなる	
  
依存先クラス	
  

メールサーバ
再掲 :	
  各クラスを new	
  で繋いだ場合	
DAO/Repository	
Service	
REST	
  
Endpoint	

new	

テスト	
対象	
ClassA	
  

new	

new	

さらなる	
  
依存先クラス	
  

依存先	
  
クラス	
  

DBMS	

ユニットテストに	
JAX-­‐WS	
  Client	
Service	
依存先	
  
クラス	
  

必要なクラス	
new	

さらなる	
  
依存先クラス	
  

Mail	
  Client	
new	

関連他システム	

さらなる	
  
依存先クラス	
  

メールサーバ
結果UTもしやすく、クラス間の依存も下がる	
DAO/Repository	
さらなる	
  
依存先クラス	
  

Service	
インタフェース	
  

REST	
  
Endpoint	

テスト	
対象	
ClassA	
  

call	
フィールド
にセット	

DBMS	

call	
フェイク実装	
  

new	
ユニットテストに	

必要なクラス	
Service	

インタフェース	
  

JAX-­‐WS	
  Client	
さらなる	
  
依存先クラス	
  

Mail	
  Client	
フェイク実装	
  

new	
JUnitテストケース	
  

関連他システム	

さらなる	
  
依存先クラス	
  

メールサーバ
DIの主なメリット	
各クラス間の依存性を弱めることができる	
•  特にユニットテストしにくい外部リソースへの依存に効果的	
  
•  データベースへのアクセス	
  
•  メールの送信	
  
•  他システムとの連携	
  

•  インタフェースの切り出しとDIをセットで使う	
  
•  インタフェースに依存させて実装を差し替えやすくする	
  

•  結果的に依存の連鎖を止めることができる	
  
CDIはここまで説明したDIコンテナの	
  
Java	
  EE	
  版 仕様です	
  
CDIについて
Context And Dependency Injection

(コンテキストと依存性の注入) 	
• 

Java EE 6 から CDI1.0 導入	

• 

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

• 

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

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

GlassFish 4.0

CDI1.1 準拠	

WildFly8

CDI1.1 準拠予定	

JBoss AS 7

CDI1.0 準拠	

Tomee 1.x

CDI1.0 準拠
Java	
  EE	
  仕様の中でのCDI位置づけ	
• 

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

• 

EJB を使わないビジネスロジックの実現	
→ Java EE 5 まではEJBのみDIができた	
Client	

Java EE 7 Specifications	
Web 層	

JSF	

PCブラウザ	

ビジネス 層	
EJB	

JAX-RS	

CDI

WebSocket	

モバイル	

EIS	

永続化層	

EJBを使わない

ビジネスロジックの実現	

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

JPA	
RDBMS 等
CDIの代表的な機能	
  
•  実装インスタンスのインジェクション @Inject	
  
-  静的な型解決 @Qualifiler	
  
-  動的な型解決 @Produces	
  	
  
•  スコープ @RequestScoped,	
  @SessionScoped	
  など	
  
•  EL式との組み合わせ	
  
•  インターセプタ @InterceptorBinding	
  
•  コンフィグ beans.xml
CDIの代表的な機能	
  
•  実装インスタンスのインジェクション @Inject	
  
-  静的な型解決 @Qualifiler	
  
-  動的な型解決 @Produces	
  	
  
•  スコープ @RequestScoped,	
  @SessionScoped	
  など	
  
•  EL式との組み合わせ	
  
•  インターセプタ @InterceptorBinding	
  
•  コンフィグ beans.xml
例 :	
  Servlet	
  に @Inject	
  する	
  
@WebServlet(“/sample”)	
  
public	
  class	
  SampleServlet	
  extends	
  HcpServlet	
  {	
  
	
  	
  	
  	
  @Inject	
  
	
  	
  	
  	
  private	
  Service	
  service;	

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	
  

call	

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

ServiceImpl	
  

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

•  Servlet	
  関連 @WebServlet	
  	
  	
  @WebFilter	
  	
  	
  @WebListener	
  
•  EJB	
  Session	
  Bean	
   :	
  @Stateless	
  など	
  
•  JAX-­‐RS	
  RESTエンドポイント :	
  @Path	
  など	
  
•  CDIによって生成されたインスタンス	
  
CDIによって生成されたインスタンスには注入可能	

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

public class ServiceImpl
implements Service {
@Inject
Repository repository;

実装クラスServiceImplの	
  
インスタンスをインジェクション
CDIによって生成されたインスタンスには注入可能	
CDIによって	
  
インスタンス生成	
@Path(“/test”)
public class SampleResource {
@Inject
Service service;

public class ServiceImpl
implements Service {
@Inject
Repository repository;
CDIによって生成されたインスタンスには注入可能	
CDIによって	
  
インスタンス生成	
@Path(“/test”)
public class SampleResource {
@Inject
Service service;

public class ServiceImpl
implements Service {
@Inject
Repository repository;

public class RepositoryImpl
implements Repository {…}

さらなるインジェクションが可能
CDIに生成される側の条件	
  	
  
引数なしコンストラクタがあれば、どんなクラスも注入可能	

REST	
  Endpoint	
  等	
  

call	

<<interface>>	
  

Service	
  

ServiceImpl	
  
CDIに生成される側	

•  引数なしコンストラクタを含むクラス	
  
•  インタフェースの実装はなくても @Inject	
  でインジェクション可能	
  
•  アノテーションもいらない完全なPOJO	
  (Plain	
  Old	
  Java	
  Object)	
  
CDIの代表的な機能	
  
•  実装インスタンスのインジェクション @Inject	
  
-  静的な型解決 @Qualifiler	
  
-  動的な型解決 @Produces	
  	
  
•  スコープ @RequestScoped,	
  @SessionScoped	
  など	
  
•  EL式との組み合わせ	
  
•  インターセプタ @InterceptorBinding	
  
•  コンフィグ beans.xml
インタフェースの実装が複数ある場合は?	
  
A.  インジェクションフィールドがnullのまま	
  
B.  デプロイに失敗する	
  
C.  最初にロードしたクラスをインジェクション	
インジェクション先コード	

@Inject	
  
private	
  DAO	
  dao;	

実装クラスが複数ある	
OracleDAO	
  

<<interface>>	
  

DAO	
  

PostgresDAO	
  
インタフェースの実装が複数ある場合は?	
  
A.  インジェクションフィールドがnullのまま	
  
B.  デプロイに失敗する	
  
C.  最初にロードしたクラスをインジェクション	
インジェクション先コード	

@Inject	
  
private	
  DAO	
  dao;	

実装クラスが複数ある	
OracleDAO	
  

<<interface>>	
  

DAO	
  

PostgresDAO	
  
静的な型解決	
  :	
  Qualifier	
  (修飾子) の使用	
1.	
  @Qualifier	
  が付与されたアノテーションを作成	

@Qualifier	
  
@RetenOon	
  (RunOme)	
  
@Target	
  ({METHOD,	
  FIELD,	
  PARAMETER,	
  TYPE})	
  
public	
  @interface	
  Oracle	
  {}	
  
静的な型解決	
  :	
  Qualifier	
  (修飾子) の使用	
2.	
  インジェクション先とBean両方に付与する	
OracleDAOをインジェクションしたい場合は@Injectと@Oracleを指定	

@Inject	
  
@Oracle	
  
private	
  DAO	
  dao;	

@Oracle	
  
public	
  class	
  OracleDAO	
  …	
@PostgreSQL	
  
public	
  class	
  PostgresDAO	
  …
静的な型解決	
  :	
  Qualifier	
  (修飾子) の使用	
3.	
  インジェクション対象を変更したい場合	
PostgresDAOをインジェクションしたい場合は修飾子を書き換える。	

@Inject	
  
@PostgreSQL	
  
private	
  DAO	
  dao;	

@Oracle	
  
public	
  class	
  OracleDAO	
  …	
@PostgreSQL	
  
public	
  class	
  PostgresDAO	
  …
実行時に実装型の解決をしたい場合	

で支払う	

ユーザA	

@Path(“/charge”)	
<<REST	
  Endpoint>>	
  

ChargeResource	
  

で支払う	

ユーザB	

<<interface>>	
  

ChargeService	
  

PaypalService	
  

SquareService	
  

ユーザに応じて実装を
変えたい
動的な型解決	
  :	
  @Produces	
@Produces	
  メソッドと限定子を併用して動的な型の解決を行う	
@Path(“/charge”)	
  
@Credit	
<<REST	
  Endpoint>>	
  

ChargeResource	
  

<<interface>>	
  

ChargeService	
  

return結果をInject	
@Credit	
  @Produces	
<<Producer>>	
  

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

PaypalService	
  
依存	

SquareService	
  
依存
プロデューサのコード例	

@RequestScoped	
  
public	
  class	
  PaymentStrategy	
  {	
  

@Path(“/charge”)	

	
  	
  	
  	
  private	
  PaymentType	
  paymentType;	
  
<<REST	
  Endpoint>>	
  
ChargeResource	
  

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

ChargeService	
  

	
  	
  	
  @Credit	
  @Produces	
  
	
  	
  	
  	
  public	
  ChargeService	
  getStrategy(PaypalService	
  paypal,	
  SqureService	
  square)	
  {	
  
return結果をInject	
	
  	
  	
  	
  	
  	
  	
  	
  switch	
  (paymentType)	
  {	
  
PaypalService	
  
SquareService	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  case	
  P@Produces	
 paypal;	
  
ayPal	
  :	
  return	
  
<<Producer>>	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  case	
  Square	
  :	
  return	
  square;	
  
PaymentStrateg
依存	
依存	
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
y	
  
	
  	
  	
  	
  }	
  

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

@RequestScoped	
  
public	
  class	
  PaymentStrategy	
  {	
  

@Path(“/charge”)	

	
  	
  	
  	
  private	
  PaymentType	
  paymentType;	
  
<<REST	
  Endpoint>>	
  
ChargeResource	
  

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

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

	
  	
  	
  @Credit	
  @Produces	
  
	
  	
  	
  	
  public	
  ChargeService	
  getStrategy(PaypalService	
  paypal,	
  SqureService	
  square)	
  {	
  
return結果をInject	
	
  	
  	
  	
  	
  	
  	
  	
  switch	
  (paymentType)	
  {	
  
PaypalService	
  
SquareService	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  case	
  P@Produces	
 paypal;	
  
ayPal	
  :	
  return	
  
<<Producer>>	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  case	
  Square	
  :	
  return	
  square;	
  
PaymentStrateg
依存	
依存	
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
y	
  
	
  	
  	
  	
  }	
  

	
  	
  	
  	
  …	
限定子を忘れると、型が不定となるデプロイエラーが発生するので注意
プロデューサメソッドのコード例	

@RequestScoped	
  
public	
  class	
  PaymentStrategy	
  {	
  

@Path(“/charge”)	

	
  	
  	
  	
  private	
  PaymentType	
  paymentType;	
  
<<REST	
  Endpoint>>	
  
ChargeResource	
  

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

ChargeService	
  

	
  	
  	
  @Credit	
  @Produces	
  
	
  	
  	
  	
  public	
  ChargeService	
  getStrategy(PaypalService	
  paypal,	
  SqureService	
  square)	
  {	
  
return結果をInject	
	
  	
  	
  	
  	
  	
  	
  	
  switch	
  (paymentType)	
  {	
  
SquareService	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  case	
  P@Produces	
 paypal;	
   PaypalService	
  
ayPal	
  :	
  return	
  
<<Producer>>	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  case	
  Square	
  :	
  return	
  square;	
   実装インスタンスはメソッド引数に	
  
PaymentStrateg
依存	
依存	
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
y	
  
	
  	
  	
  	
  }	
  

	
  	
  	
  	
  …	

APサーバから渡される	
  
プロデューサメソッドのコード例	

@RequestScoped	
  
public	
  class	
  PaymentStrategy	
  {	
  

@Path(“/charge”)	

	
  	
  	
  	
  private	
  PaymentType	
  paymentType;	
  
<<REST	
  Endpoint>>	
  
ChargeResource	
  

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

ChargeService	
  

	
  	
  	
  @Credit	
  @Produces	
  
	
  	
  	
  	
  public	
  ChargeService	
  getStrategy(PaypalService	
  paypal,	
  SqureService	
  square)	
  {	
  
return結果をInject	
	
  	
  	
  	
  	
  	
  	
  	
  switch	
  (paymentType)	
  {	
  
PaypalService	
  
SquareService	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  case	
  P@Produces	
 paypal;	
  
ayPal	
  :	
  return	
  
<<Producer>>	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  case	
  Square	
  :	
  return	
  square;	
  
PaymentStrateg
依存	
依存	
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
インジェクションしたい実装を	
  
y	
  
	
  	
  	
  	
  }	
  

	
  	
  	
  	
  …	

条件に応じてreturnする。	
  
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	
  :	
  ログイン~ログアウト	
  

クライアント	

サーバ	
Login	

Logout	

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

同一セッション中は、状態が保持された	
  
同じインスタンスがインジェクションされる	
  
@ConversaOonScoped	
  :	
  Session未満の任意長さ	
  

クライアント	

サーバ	
Login	
Begin	

End	
Logout	

@Named	
  
@ConversaOonScoped	
  
public	
  class	
  ConversaOonController	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  implements	
  Serializable	
  {	
  
	
  
	
  	
  	
  	
  @Inject	
  
	
  	
  	
  	
  private	
  ConversaOon	
  conversaOon;	
  
	
  
	
  	
  	
  	
  public	
  void	
  begin()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  …	
  
	
  	
  	
  	
  	
  	
  	
  	
  conversaOon.begin();	
  
	
  	
  	
  	
  }	
  
	
  
	
  	
  	
  	
  public	
  void	
  end()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  …	
  
	
  	
  	
  	
  	
  	
  	
  	
  conversaOon.end();	
  
	
  	
  	
  	
  }	
  
アプリケーションスコープの使い分け	
  
@Startupや@Lockが使いたい場合はEJBがお勧め。	
似たような機能が複数ある	
•  アプリケーションスコープ

@javax.enterprise.context.ApplicaOonScoped	
  

•  JSR-330のシングルトン

@javax.inject.Singleton	
  

•  EJBのシングルトン

@javax.ejb.Singleton	
  

@ApplicaOonScoped	
  
(CDI)	

@Singleton	
  
(JSR-­‐330)	

@Singleton	
  
(EJB)	

生存期間	
  

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

同じ	

同じ	

デプロイ時初期化	
  

ない	
  

ない	
  

@WebListnerと組合せが必要	
  

左記に同じ	
  

ある	

@Lock	
  

ない	
  

ない	
  

ある	

シリアライズ対応	
  
(クラスタ考慮?)	
  

ある	

ない	
  

仕様に言及なし	
  

@Startup	
  

ロック制御	
  
@Dependent	
  :	
  インジェクション先に合わせる (default)	
  
Servlet	
  

call	

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

<<interface>>	
  

Service	
  
ServiceImpl	
  

@WebServlet(“/sample”)	
  
public	
  class	
  SampleServlet	
  extends	
  HcpServlet	
  {	
  
サーブレット生成時に	
  
	
  	
  	
  	
  @Inject	
  
一度だけインジェクション	
  
	
  	
  	
  	
  private	
  Service	
  service;	
  
	
  
//	
  デフォルトは @Dependent	
  であると暗黙的に判定	
  
public	
  class	
  ServiceImpl	
  extends	
  Service	
  {…}
CDIで使用可能なスコープ一覧	
  
スコープ	
•  リクエストスコープ

@javax.enterprise.context.RequestScoped	
  

•  会話スコープ

@javax.enterprise.context.ConversaOonScoped	
  

•  セッションスコープ

@javax.enterprise.context.SessionScoped	
  

•  アプリケーションスコープ

短い	

@javax.enterprise.context.ApplicaOonScoped	
  
長い	

擬似スコープ (pseudo	
  scope)	
•  依存先に応じる(デフォルト)	
  	
  	
  @javax.enterprise.context.Dependent	
  
•  シングルトン

	
  @javax.inject.Singleton	
  
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
インターセプタとは	
  
メソッドの開始・終了に割込み,業務とは直接関連ないシステム処理を実行	
共通処理	

課金業務クラス	
  
注文受付クラス	
  
発送業務クラス	
  

Interceptor	

メソッド開始	

Interceptor	

共通処理	

代表的なインターセプタ	
  
•  ロギング	
  
•  セキュリティ関連 (認証や認可処理)	
  
•  トランザクションの開始、コミット、ロールバック制御	
  

完了
インターセプタの作り方	
  
@InterceptorBindingを付与した自作アノテーションで実装と対象を関連付け	
1.	
  アノテーション作る	

2.	
  インターセプタ実装を作る	

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

@Logging	
  @Interceptor	
  
public	
  class	
  LoggingInterceptor	
  {	
  
	
  	
  …	
  
	
  	
  @AroundInvoke	
  
	
  	
  public	
  void	
  log(InvocaOonContext	
  ic)	
  {	
  
	
  	
  	
  	
  	
  	
  logger.debug(“log	
  message”);	
  
	
  	
  	
  	
  	
  	
  return	
  ic.proceed();	
  
	
  	
  }	
3.	
  インターセプタ対象にバインドさせる	

@Logging	
  
public	
  void	
  charge(int	
  amount)	
  {…}	
  
インターセプタの優先順位は?	
  
インターセプタの順序が重要な場合も多くある。	

セキュリティ処理	

3

2
ロギング処理	

1

開始	

トランザクション開始	

インターセプタ順序を定義したい	
業務処理	
課金業務クラス	
  
注文受付クラス	
  
発送業務クラス	
  

終了
インターセプタとコンフィグ	
  
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	
  ではbeans.xmlが必須、EE	
  7	
  からはオプション化	
•  Java	
  EE	
  6	
  の場合 :	
  WEB-­‐INF/beans.xml	
  を含めるとCDIが有効化	
インターセプタがない場合は、	
  
中身は空ファイルで良い。	

•  Java	
  EE	
  7	
  の場合 :	
  beans.xmlなしで有効化されるが、スコープ指定が必須	
インジェクション先のスコープと同じにする場合でも、	
  
省略せずに明示的に @Dependent	
  を付与する。	

@Dependent
public class ServiceImpl implements .. {
CDIを Java	
  EE	
  アプリでどう使うか
3層モデルの依存性をDIで繋ぐ	
技術の変化が激しい部分は、ロジックとは別層 (クラス)に切り出す	
Java EE の 3層アーキテクチャ	
Web 層	
REST	
  Endpoint	
  
(JAX-­‐RS2.x)	
  
BackingBean	
  
(JSF2.x)	
  

ビジネス 層	

永続化層	

Service	
  
(CDI	
  Bean)	
  

Repository	
  
(JPA2.x)	
  
RDBMS	

クライアント	

WebSocket	
  

Servlet	
  

RDBMS以外の	
  
永続化機構	
  
(KVSなど)
3層モデルの依存性をDIで繋ぐ	
ビジネスロジックは特定技術に依存したくない	
Java EE の 3層アーキテクチャ	
Web 層	
REST	
  Endpoint	
  
(JAX-­‐RS2.x)	
  

ビジネス 層	

永続化層	

Service	
  
(CDI	
  Bean)	
  

Repository	
  
(JPA2.x)	
  
RDBMS	

BackingBean	
  
(JSF2.x)	
  
クライアント	

WebSocket	
  

Servlet	
  

業務例 :	
  	
  
・ 電話設備の登録/削除を行う	
  
・ 支払いがなければ督促する	
  
WebSocketが出ても、KVSが出ても	
  
業務ロジックコードは変えたくない	
  

RDBMS以外の	
  
永続化機構	
  
(KVSなど)
3層モデルの依存性をDIで繋ぐ	
シンプルに new	
  で繋いでいくと …	
  	
  
Java EE の 3層アーキテクチャ	
Web 層	
REST	
  Endpoint	
  
(JAX-­‐RS2.x)	
  
BackingBean	
  
(JSF2.x)	
  

永続化層	

ビジネス 層	
new	
new	

Service	
  
(CDI	
  Bean)	
  

new	

Repository	
  
(JPA2.x)	
  
RDBMS	

クライアント	

WebSocket	
  

Servlet	
  

RDBMS以外の	
  
永続化機構	
  
(KVSなど)
3層モデルの依存性をDIで繋ぐ	
冒頭の通り依存性が強くテストできない等 の課題	
Java EE の 3層アーキテクチャ	
Web 層	
REST	
  Endpoint	
  
(JAX-­‐RS2.x)	
  

永続化層	

ビジネス 層	
new	
new	

Service	
  
(CDI	
  Bean)	
  

new	

Repository	
  
(JPA2.x)	
  
RDBMS	

BackingBean	
  
(JSF2.x)	
  

クライアント	

テスト	
対象	
WebSocket	
  

Servlet	
  

テストに必要	
RDBMS以外の	
  
永続化機構	
  
(KVSなど)
3層モデルの依存性をDIで繋ぐ	
@Injectでユニットテストしやすく、依存性を少なく。	
Java EE の 3層アーキテクチャ	
Web 層	

クライアント	

REST	
  Endpoint	
  
(JAX-­‐RS2.x)	
  

ビジネス 層	

永続化層	

Service	
  
(CDI	
  Bean)	
  

Repository	
  
(JPA2.x)	
  
RDBMS	

REST処理	

@Path(“/sample”)	
  
public	
  class	
  Resource	
  {	
  
	
  	
  @Inject	
  
	
  	
  private	
  Service	
  service;	
  

業務処理	

DBアクセス	

public	
  class	
  Service	
  {	
  

public	
  class	
  Repository	
  {	
  

	
  	
  @Inject	
  
	
  	
  private	
  Repository	
  …	
  

	
  	
  @PersistenceContext	
  
	
  	
  private	
  EnOtyManager	
  ..	
  
インジェクション	

インジェクション
EJBとの使い分け
@Transactional の導入 (Java EE 7)	
EJBの宣言的トランザクションがCDIでもできるようになった	

•  Spring	
  の@TransacOonalと同じように使える	
  
•  RunOmeExcepOonがthrowされたら自動的にロールバック	

public	
  class	
  BankService	
  {	
  
	
  	
  	
  	
  …	
  
	
  	
  	
  	
  //	
  口座振り替えメソッド	
  
	
  	
  	
  	
  @TransacOonal(TransacOonal.TxType.REQUIRED)	
  
	
  	
  	
  	
  public	
  void	
  transfer(int	
  amount)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  pay(amount);	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  振り込み元から出金	
  
	
  	
  	
  	
  	
  	
  	
  	
  receipt(amount);	
  	
  	
  	
  //	
  振込み先に入金	
  
	
  	
  	
  	
  }
CDIとEJBの機能の比較	
CDI1.1	
ある	
  
(@Inject	
  等)	

ある	
  
(@Named)	

ある	
  
(@RequestScoped	
  等)	

ある	
  

EJB3.1	
ある	
  

DI/AOP	
  

(@Inject,	
  @EJB	
  等)	

EL式連携	
  

ない	
  

スコープ	
  

ない	
  
(@Stateless	
  or	
  @Stateful)	
  

(@TransacOonal)	

宣言的	
  
トランザクション	
  

(@Stateless	
  or	
  @Stateful)	
  

ない	
  

非同期実行	
  

ある	
  

ない	
  

MQ連携	
  

ない	
  

リモート実行	
  

ない	
  

タイマ機能	
  

ある	
  

(@Asynchronous)	
  

ある	
  
(@MDB)	
  

ある	
  
(@Remote)	
  

ある	
  
(@Schedule)	
  
Web構築にはCDIで十分、基幹機能はEJB継続使用	
CDI1.1	
ある	
  
(@Inject	
  等)	

ある	
  

(@Named)	
Web構築	
ある	
  
に使う	
)	
(@RequestScoped	
  等

ある	
  

EJB3.1	
ある	
  

DI/AOP	
  

(@Inject,	
  @EJB	
  等)	

EL式連携	
  

ない	
  

スコープ	
  

ない	
  
(@Stateless	
  or	
  @Stateful)	
  

(@TransacOonal)	

宣言的	
  
トランザクション	
  

(@Stateless	
  or	
  @Stateful)	
  

ない	
  

非同期実行	
  

ある	
  

ない	
  

MQ連携	
  

ない	
  

リモート実行	
  

ない	
  

タイマ機能	
  

ある	
  

(@Asynchronous)	
  

ある	
  

(@MDB)	
  
基幹システムで	
使う	
ある	
  
(@Remote)	
  

ある	
  
(@Schedule)	
  
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	
  

©	
  O’Reilly	
  Media,	
  Inc.	
  	

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

•  書籍 :	
  Apress	
  Beginning	
  Java	
  EE	
  7	
  
•  hcp://www.apress.com/9781430246268	
©	
  Apress	
  Media	
  LLC
hcps://glassfish.java.net/download.html	

GlassFish4	
  を今すぐダウンロードして是非試してみてください!	
  
ご清聴ありがとうございました。	
OracleとJavaは、Oracle	
  CorporaOon	
  及びその子会社、関連会社の米国及びその他の国における登録商標です。	
  
文中の社名、商品名等は各社の商標または登録商標である場合があります。

More Related Content

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