CDI 1.0 事始め の編集履歴

nishikawa が 2015-03-28 15:53 に編集

--- Ver.7	2015-03-28 12:51:16+09:00
+++ Ver.8	2015-03-28 15:53:14+09:00
@@ -32,7 +32,7 @@
 
 Pruning と呼ばれる概念も追加されました。Pruning とは、残す価値が低い仕様を廃止していくというものです。JavaEE6 では EJB2 の Entity Bean と JAX-RPC が候補に上がっているようです。
 
-開発容易性の向上は、JavaEE6 の前身である JavaEE5 から取り組まれるようになった課題です。XML などを使った外部設定をできるだけ書かずに済むように、Configuration-by-Exception (必要なな場合のみデフォルト値を上書きする方法) という方針のもと API の策定がなされています。
+開発容易性の向上は、JavaEE6 の前身である JavaEE5 から取り組まれるようになった課題です。XML などを使った外部設定をできるだけ書かずに済むように、Configuration-by-Exception (必要な場合のみデフォルト値を上書きする方法) という方針のもと API の策定がなされています。
 
 EoD 促進の結果として、JavaEE6 の API にはおびただしい数のアノテーションが定義されています。外部設定や手続き的な API を避けようという動きの結果です。ブラックボックス化が行き過ぎていて、逆に分かりにくい部分も決して少なくないというきらいがあります。
 
@@ -214,7 +214,7 @@
 
 ## CDI による DI
 
-CDI では、DI クラスについては何もアノテーションをつける必要はありません [^1]。依存する側のクラスの定義を、CDI を利用するよう変えていきます:
+CDI では、依存される側のクラスについては何もアノテーションをつける必要はありません [^1]。依存する側のクラスの定義を、CDI を利用するよう変えていきます:
 
 ```java
 // NotificationService.java
@@ -924,7 +924,7 @@
 
 ![client-proxy-seq.png](/rambo/static/images/ce0c2aa5-accd-43fd-8806-70cea1fbcc84.png)
 
-`@ApplicationScoped`, `@SessinoScoped` でライフサイクルが明示されたオブジェクトに対する呼び出しは、そのプロキシオブジェクトの呼び出しになります。プロキシ内では呼び出し元や呼び出されたスレッドなどを元に適切なオブジェクトを生成、選択し、処理を移譲します。
+`@ApplicationScoped`, `@SessionScoped` でライフサイクルが明示されたオブジェクトに対する呼び出しは、そのプロキシオブジェクトの呼び出しになります。プロキシ内では呼び出し元や呼び出されたスレッドなどを元に適切なオブジェクトを生成、選択し、処理を移譲します。
 
 ライフサイクルの例で出したプログラムを書き換え、クライアントプロキシの存在を確認してみます:
 

nishikawa が 2015-03-28 12:51 に編集

--- Ver.6	2015-03-28 12:39:41+09:00
+++ Ver.7	2015-03-28 12:51:16+09:00
@@ -958,5 +958,11 @@
 
 CDI 仕様は、仕様書ページ数こそ 100 ページ程度とさほど多いものではないものの、機能はそれなりに豊富で、かつ他の仕様にまたがっている部分が多々あるため、複雑です。かといって「複雑で使い物にならない!」というものではなく、「DI や Context だけ使おう」といった具合に、分かりやすいところだけでも十分に使いでのある仕様だと思います。
 
+# 参考URL
+
+* [CDI 1.0 仕様書](http://docs.jboss.org/cdi/spec/1.0/html/)
+* [Contexts & Dependecy Injection for Java](http://cdi-spec.org/)
+* [Java EE 6 Technologies](http://www.oracle.com/technetwork/java/javaee/tech/javaee6technologies-1955512.html)
+
 [^1]: CDI1.1 (JavaEE7) からは仕様が変わります
 

nishikawa が 2015-03-28 12:39 に編集

--- Ver.5	2015-03-28 11:50:00+09:00
+++ Ver.6	2015-03-28 12:39:41+09:00
@@ -1,4 +1,4 @@
-従来 Java で DI を用いたい場合には、SpringやGuiceに代表される、サードパーティ製の DI コンテナを用いる必要がありました。
+従来 Java で DI を用いたい場合には、Spring や Guice に代表される、サードパーティ製の DI コンテナを用いる必要がありました。
 
 CDI は、JavaEE6 の標準仕様に組み込まれた DI と、コンテナが管理する JavaBeans のライフサイクルに関する API 仕様です。標準仕様の一部ですから、JavaEE6 準拠を名乗るアプリケーションサーバー上であれば、サードパーティ製のライブラリに頼ることなく DI を利用することができます。
 
@@ -261,7 +261,7 @@
 
 ## JSR-330 との関係について
 
-実は CDI の DI 仕様というのは、別の JSR で策定された仕様です。ここまで「CDI の DI」と呼んできた機能は、厳密に言うと JSR-330 (Dependency Injection for Java) という仕様で定義された DI 機能です。CDI の DI 部分は JSR-330 に乗っかっていて、そこにコンテキストやデコレータ、イベントやデプロイの仕様を追加したのが CDI (JSR-299) になります。
+実は CDI の DI 仕様というのは、別の JSR で策定された仕様です。ここまで「CDI の DI」と呼んできた機能は、厳密に言うと JSR-330 (Dependency Injection for Java) という仕様で定義された DI 機能です。CDI の DI 部分は JSR-330 に乗っかっていて、そこにコンテキストや DI に関する追加仕様、デコレータ、イベントやデプロイの仕様を追加したのが CDI (JSR-299) になります。
 
 もともとは CDI 一本で行こうとしていたところが、CDI の仕様が膨らんできたことで、DI だけを独立した仕様にするという動きが出てきたようです。
 

nishikawa が 2015-03-28 11:50 に編集

--- Ver.4	2015-03-28 11:16:40+09:00
+++ Ver.5	2015-03-28 11:50:00+09:00
@@ -10,9 +10,11 @@
 
 CDIに関する話題に入る前に、JavaEE6 について簡単に解説しておきます。
 
-JavaEE とは、企業向け Java 標準仕様です。その昔は J2EE と呼ばれていたものの後継にあたります。JavaEE6 は 2009年にリリースされ、現在では主要なアプリケーションサーバーがこの仕様に準拠しています。
-
-EJB や Servlet といった古くからある仕様のバージョンアップや、CDI や JAX-RS といった新しい仕様の取り込みがなされました。方向性としては JavaEE5 時代から取り組まれている開発容易性 (EoD) の促進と、モジュール化の促進、コンテナの軽量化があります。
+JavaEE (Java Platform, Enterprise Edition) とは、企業向け Java 標準仕様です。その昔は J2EE と呼ばれていたものの後継にあたります。JavaEE6 は 2009年にリリースされ、現在では主要なアプリケーションサーバーがこの仕様に準拠しています。
+
+EJB や Servlet といった古くからある仕様のバージョンアップや、CDI や JAX-RS といった新しい仕様の取り込みがなされました。方向性としては JavaEE5 時代から取り組まれている開発容易性 (EoD) の促進と、モジュール化、コンテナの軽量化があります。
+
+以下、JavaEE6 の全体図です (JSR-316 より):
 
 ![javaee6-architecture.png](/rambo/static/images/f695a885-1bb5-4457-bd29-a3edc4b77539.png)
 
@@ -28,17 +30,17 @@
 
 JavaEE6 では全 API をカバーする Full Profile と Web アプリケーションの開発に必要な API セットとして Web Profile を定義しています。Web Profileは Servlet や JSP といった Web 関連の技術だけではなく、JPA や JTA といったデータベース接続のための API も含んでいるのが特徴です。
 
-Pruning と呼ばれる概念も追加されました。これは古く、かつ残す価値が低い仕様を廃止していくというものです。JavaEE6 では EJB2 の Entity Bean と JAX-RPC が候補に上がっているようです。
+Pruning と呼ばれる概念も追加されました。Pruning とは、残す価値が低い仕様を廃止していくというものです。JavaEE6 では EJB2 の Entity Bean と JAX-RPC が候補に上がっているようです。
 
 開発容易性の向上は、JavaEE6 の前身である JavaEE5 から取り組まれるようになった課題です。XML などを使った外部設定をできるだけ書かずに済むように、Configuration-by-Exception (必要なな場合のみデフォルト値を上書きする方法) という方針のもと API の策定がなされています。
 
-EoD 促進の結果として、JavaEE6 の API にはおびただしい数のアノテーションが定義されています。手続き的な API を避けようという動きの結果です。ブラックボックス化が行き過ぎていて、逆に分かりにくい部分も決して少なくないというきらいがあります。
-
-また、同じような機能を提供するアノテーションが複数のコンポーネントで定義されていたりするのも混乱の元です。例えば今回取り上げる CDI の DI 機能も、EJB では `@EJB` という EJB 専用のアノテーションが設けられていたり、JAX-RS では `@Context` という JAX-RS 専用のアノテーションが設けられていたり、といった具合です。
+EoD 促進の結果として、JavaEE6 の API にはおびただしい数のアノテーションが定義されています。外部設定や手続き的な API を避けようという動きの結果です。ブラックボックス化が行き過ぎていて、逆に分かりにくい部分も決して少なくないというきらいがあります。
+
+また、同じような機能を提供するアノテーションが複数のコンポーネントで定義されていたりするのも混乱の元です。例えば今回取り上げる CDI の DI 機能も、EJB では `@EJB` という EJB 専用のアノテーションが設けられていたり、JAX-RS では `@Context` という JAX-RS 専用のアノテーションが設けられていたり、といった具合です。今後のバージョンアップで、この辺の仕様の整理がなされていくことを期待しています。
 
 ## 実装
 
-JavaEE6 準拠を謳うには CTS (Compatibility Test Suite) に通過する必要があります。Oracle のページに、公式に認められた JavaEE6 準拠のアプリケーションサーバーが一覧化されています:
+JavaEE6 準拠を謳うには CTS (Compatibility Test Suite) に通過する必要があります。[Oracle のページ](http://www.oracle.com/technetwork/java/javaee/overview/compatibility-jsp-136984.html)に、公式に認められた JavaEE6 準拠のアプリケーションサーバーが一覧化されています:
 
 サーバー | Full | Web
 ------- | ---- | --------
@@ -62,11 +64,7 @@
 TongTech TongWeb Application Server 6 | X | O
 IBM WebSphere Application Server Version 8.5.5 (Liberty Profile) | X | O
 
-以下のページに公式なアナウンスがなされています:
-
-[Java EE Compatibility (www.oracle.com)](http://www.oracle.com/technetwork/java/javaee/overview/compatibility-jsp-136984.html)
-
-JavaEE6 の中で、比較的使用頻度の高そうな仕様をピックアップして紹介します (CDI は除く)。
+以下、JavaEE6 の中で、比較的使用頻度の高そうな仕様をピックアップして紹介します (CDI は除く)。
 
 ## JPA 2.0 (JSR-317)
 
@@ -97,7 +95,7 @@
 
 ## なぜ今 JavaEE6 なのか
 
-2013年に JavaEE6 の後継となる JavaEE7 がリリースされました。JavaEE6 の流れを組んだ、新しい仕様です。JavaEE6 では行き届かなかった細かい改善点が数多く見られ、JavaEE7 が使えるのであれば JavaEE7 を選択すべきだと思います。
+2013年に JavaEE6 の後継となる JavaEE7 がリリースされました。JavaEE6 の流れを組んだ、新しい仕様です。JavaEE6 では行き届かなかった細かい改善点が数多く見られ、JavaEE6 と JavaEE7 のどちらを使うか選べるのであれば、JavaEE7 を選択すべきだと思います。
 
 しかし [Java EE Compatibility](http://www.oracle.com/technetwork/java/javaee/overview/compatibility-jsp-136984.html) を見ればわかるように、JavaEE7 準拠のアプリケーションサーバーは非常に少ないという現状があります (2015/3 現在)。この現状を踏まえ、現実のプロジェクトで JavaEE7 が採用されるのはまだまだ先になりそうであるということで、今回は比較的実装が多い JavaEE6 を取り上げました。
 
@@ -189,7 +187,7 @@
 }
 ```
 
-手動の場合、どうにか自力で `MailNotifier` のインスタンスと、`NotificationService` のインスタンスを得る必要があります。今回は依存性のルートから new してインスタンス化します。
+手動の場合、どうにか自力で `MailNotifier` のインスタンスと、`NotificationService` のインスタンスを得る必要があります。今回はオブジェクトツリーのルートにあたる `MyServlet` から new してインスタンス化します。
 
 ```java
 @WebServlet(urlPatterns = { "/di/cdi" })
@@ -212,6 +210,8 @@
 
 `NotificationService` のコンストラクタで `Notifier` への依存性を注入しています。この実装では `NotificationService` から `Notifier` への依存性は外部から注入できますが、`MyServlet` から `NotificationService`, `Notifier` への依存性は外部から注入することができません。この程度の規模であれば少しの修正で対応できるでしょうが、規模が大きくなってくると、実装の煩わしさが常について回ります。
 
+また、今回は `doGet` の中で各インスタンスを new しましたが、もっと広いスコープでインスタンス化し、それを使いまわしたい場合には、別の工夫が必要になってきます。
+
 ## CDI による DI
 
 CDI では、DI クラスについては何もアノテーションをつける必要はありません [^1]。依存する側のクラスの定義を、CDI を利用するよう変えていきます:
@@ -244,27 +244,26 @@
 }
 ```
 
-ここでは簡単に実行できるように Servlet にしました。CDI では依存性のルートに当たるクラスについては、いくつかの条件が設けられています。
-
- * Servlet や EJB など、JavaEE アプリケーションサーバーによってライフサ
-   イクルを管理されるもの
+ここでは簡単に実行できるように Servlet にしました。CDI では依存性のルートに当たるクラスについては、いくつかの条件が設けられています:
+
+ * Servlet や EJB など、JavaEE アプリケーションサーバーによってライフサイクルを管理されるもの
  * CDI のスコープを明示していること
 
 といったところで、その一つを満たせばよいことになっています。
 
 これ以外は特に設定なども必要ありません。依存性を注入したい場所に `@Inject` をつけておけば、アプリケーションサーバー上で稼働する CDI コンテナによって依存関係が解決されます。
 
-ただし CDI を有効にするためのファイルだけ作っておく必要があります。[^1]
-
-```
-$ touch cditutor/WEB-INF/beans.xml
+ただし CDI 自体を有効にするためのファイルだけ作っておく必要があります。[^1]
+
+```
+$ touch src/main/webapp/WEB-INF/beans.xml
 ```
 
 ## JSR-330 との関係について
 
 実は CDI の DI 仕様というのは、別の JSR で策定された仕様です。ここまで「CDI の DI」と呼んできた機能は、厳密に言うと JSR-330 (Dependency Injection for Java) という仕様で定義された DI 機能です。CDI の DI 部分は JSR-330 に乗っかっていて、そこにコンテキストやデコレータ、イベントやデプロイの仕様を追加したのが CDI (JSR-299) になります。
 
-もともとは CDI 一本で行こうとしていたところが、CDI が膨らんできたことで、DI だけを独立した仕様にするという動きが出てきたようです。
+もともとは CDI 一本で行こうとしていたところが、CDI の仕様が膨らんできたことで、DI だけを独立した仕様にするという動きが出てきたようです。
 
 DI コンテナの実装である Google Guice は JSR-330 の参照実装ですが、JSR-299 の参照実装ではありません。一応この辺の境もあるということを覚えておけば、いいことがあるかもしれません(ないかもしれません)。
 
@@ -301,6 +300,8 @@
 @ConversationScoped | 会話スコープ。任意の長さ
 @Dependent | 依存元のスコープに依存。擬似スコープ
 
+※厳密にはもっと詳しい決まりがあります。JSR-299 の 6.7. Context management for built-in scopes を参照
+
 すべてアノテーションが `javax.enterprice.context` パッケージに定義されています。
 
 `@ApplicationScoped`, `@SessionScoped`, `@RequestScoped` の動きを見てみます。まずはスコープを指定したクラス (依存される側のクラス) を定義します。
@@ -504,7 +505,9 @@
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         PrintWriter pw = resp.getWriter();
-        pw.println(doc.getText().replace(" ", " "));
+        pw.println("<html><body>");
+        pw.println(doc.getText().replaceAll(" ", "&nbsp;"));
+        pw.println("</body></html>");
     }
 }
 ```
@@ -633,6 +636,7 @@
     }
 }
 
+// CurrentUser.java
 @SessionScoped
 public class CurrentUser implements Serializable {
     private static final long serialVersionUID = 1L;
@@ -801,7 +805,7 @@
 
 ## Qualifier
 
-これまで見てきた DI の例は、全て CDI の *Typesafe Resolution* という仕組みに則って、その依存性が解決されてきました。依存する側とされる側との間で型が矛盾しなければ (= 代入可能であれば)、その間に依存性を注入するというものです。
+これまで見てきた DI の例は、全て CDI の *Typesafe Resolution* という仕組みに則って、その依存性が解決されてきました。依存する側とされる側との間で型が矛盾しなければ (= 代入可能であれば)、その間に依存性を注入するというものです。この Typesafe Resolution は DI だけでなくデコレータやインターセプタ、イベント通知などにも適用される仕組みです。
 
 しかしこれだけではカバーできない場合もあります。例えばデータソースが複数の用途で分かれているとして、
 
@@ -888,7 +892,7 @@
 }
 ```
 
-こんな依存関係を組んでいたとします。`Client` のインスタンスを複数作ったとしても、`Foo` のインスタンスは `ApplicationScoped` なので 1 つしか作られません。また `Foo` が依存する `Bar` は呼び出し元のセッションに応じて切り替える必要があります。
+こんな依存関係を組んでいたとします。`Client` のインスタンスを複数作ったとしても、`Foo` のインスタンスは `@ApplicationScoped` なので 1 つしか作られません。また `Foo` が依存する `Bar` は呼び出し元のセッションに応じて切り替える必要があります。
 
 ```java
 // セッション1
@@ -920,7 +924,7 @@
 
 ![client-proxy-seq.png](/rambo/static/images/ce0c2aa5-accd-43fd-8806-70cea1fbcc84.png)
 
-`ApplicationScoped`, `SessinoScoped` でライフサイクルが明示されたオブジェクトに対する呼び出しは、そのプロキシオブジェクトの呼び出しになります。プロキシ内では呼び出し元や呼び出されたスレッドなどを元に適切なオブジェクトを生成、選択し、処理を移譲します。
+`@ApplicationScoped`, `@SessinoScoped` でライフサイクルが明示されたオブジェクトに対する呼び出しは、そのプロキシオブジェクトの呼び出しになります。プロキシ内では呼び出し元や呼び出されたスレッドなどを元に適切なオブジェクトを生成、選択し、処理を移譲します。
 
 ライフサイクルの例で出したプログラムを書き換え、クライアントプロキシの存在を確認してみます:
 
@@ -948,9 +952,9 @@
 
 # まとめ
 
-だらだらと CDI 1.0 の全容を追っかけてきました。大体の雰囲気は掴んでもらえたんじゃないかと思います。
-
-触れなかった仕様がいくつかあります。デプロイに関する仕様、CDI の拡張モジュールを作るための仕様などです。デプロイに関する仕様はデバッグ時には役立つ知識になるでしょうし、CDI の拡張モジュールは独自のスコープを定義するときに関係してきます。
+だらだらと CDI 1.0 の基本的な使い方を追ってきました。大体の雰囲気は掴んでもらえたんじゃないかと思います。
+
+独断と偏見で、基本的な使い方は外れるだろということで、今回は触れなかった仕様がいくつかあります。デプロイに関する仕様、CDI の拡張モジュールを作るための仕様などです。デプロイに関する仕様はデバッグ時には役立つ知識になるでしょうし、CDI の拡張モジュールは独自のスコープを定義するときに関係してきます。
 
 CDI 仕様は、仕様書ページ数こそ 100 ページ程度とさほど多いものではないものの、機能はそれなりに豊富で、かつ他の仕様にまたがっている部分が多々あるため、複雑です。かといって「複雑で使い物にならない!」というものではなく、「DI や Context だけ使おう」といった具合に、分かりやすいところだけでも十分に使いでのある仕様だと思います。
 

nishikawa が 2015-03-28 11:16 に編集

--- Ver.3	2015-03-28 11:09:31+09:00
+++ Ver.4	2015-03-28 11:16:40+09:00
@@ -107,7 +107,7 @@
 
 ここでは以下のような構成のオブジェクトツリーを DI で作ってみます:
 
-![di-example-diag.png](/rambo/static/images/659c408b-12dc-4dad-8ea1-0f9dcd49e5dc.png)
+![di-example-diag.png](/rambo/static/images/b73d23dc-3d4e-4f2b-819f-306214ccb98f.png)
 
 ## 手動による DI
 

nishikawa が 2015-03-28 11:09 に編集

--- Ver.2	2015-03-28 11:08:37+09:00
+++ Ver.3	2015-03-28 11:09:31+09:00
@@ -1,5 +1,3 @@
-# CDI 事始め
-
 従来 Java で DI を用いたい場合には、SpringやGuiceに代表される、サードパーティ製の DI コンテナを用いる必要がありました。
 
 CDI は、JavaEE6 の標準仕様に組み込まれた DI と、コンテナが管理する JavaBeans のライフサイクルに関する API 仕様です。標準仕様の一部ですから、JavaEE6 準拠を名乗るアプリケーションサーバー上であれば、サードパーティ製のライブラリに頼ることなく DI を利用することができます。

nishikawa が 2015-03-28 11:08 に編集

--- Ver.1	2015-03-28 10:20:55+09:00
+++ Ver.2	2015-03-28 11:08:37+09:00
@@ -1,24 +1,24 @@
 # CDI 事始め
 
-従来JavaでDIを用いたい場合には、SpringやGuiceに代表される、サードパーティ製のDIコンテナを用いる必要がありました。
-
-CDIは、JavaEE6の標準仕様に組み込まれたDIに関するAPI仕様です。標準仕様の一部ですから、JavaEE6準拠を名乗るアプリケーションサーバー上であれば、サードパーティ製のライブラリに頼ることなくDIを利用することができます。
-
-また、CDIはJavaEE6を構成するさまざまな仕様を横断した、いわば基礎的な仕様です。JavaEE6自体がモジュラーな構成をとっており、それを繋ぎあわせる役割を担っています。
-
-JavaEE6を利用するのであれば、CDIを活用しない手はありません。しかし、いくつかの仕様を横断している関係上、その仕様は難解です。今回は、そんなCDIの基本的な使い方を学んでいきます。
+従来 Java で DI を用いたい場合には、SpringやGuiceに代表される、サードパーティ製の DI コンテナを用いる必要がありました。
+
+CDI は、JavaEE6 の標準仕様に組み込まれた DI と、コンテナが管理する JavaBeans のライフサイクルに関する API 仕様です。標準仕様の一部ですから、JavaEE6 準拠を名乗るアプリケーションサーバー上であれば、サードパーティ製のライブラリに頼ることなく DI を利用することができます。
+
+また、CDI は JavaEE6 を構成するさまざまな仕様を横断した、いわば基礎的な仕様です。JavaEE6自体がモジュラーな構成をとっており、それを繋ぎあわせる役割を担っています。
+
+JavaEE6 を利用するのであれば、CDI を活用しない手はありません。しかし、いくつかの仕様を横断している関係上、その仕様は難解です。今回は、そんな CDI の基本的な使い方を学んでいきます。
 
 # Java EE 6 について
 
 CDIに関する話題に入る前に、JavaEE6 について簡単に解説しておきます。
 
-JavaEE6とは、企業向けJava標準仕様です。その昔はJ2EEと呼ばれていたものの後継にあたります。2009年にリリースされ、現在では主要なアプリケーションサーバーがこの仕様に準拠しています。
-
-EJBやServletAPIといった古くからある仕様のバージョンアップや、CDIやJAXRSといった新しい仕様の取り込みがなされました。方向性としてはJavaEE5時代から取り組まれている開発容易性(EoD)の促進と、モジュール化があります。
+JavaEE とは、企業向け Java 標準仕様です。その昔は J2EE と呼ばれていたものの後継にあたります。JavaEE6 は 2009年にリリースされ、現在では主要なアプリケーションサーバーがこの仕様に準拠しています。
+
+EJB や Servlet といった古くからある仕様のバージョンアップや、CDI や JAX-RS といった新しい仕様の取り込みがなされました。方向性としては JavaEE5 時代から取り組まれている開発容易性 (EoD) の促進と、モジュール化の促進、コンテナの軽量化があります。
 
 ![javaee6-architecture.png](/rambo/static/images/f695a885-1bb5-4457-bd29-a3edc4b77539.png)
 
-JavaEE6の特徴としては
+JavaEE6 の特徴としては
 
  * 軽量化
  * 拡張性
@@ -26,15 +26,15 @@
 
 の 3 つがあげられます。
 
-JavaEE6 で新たに導入された概念として、Profile があります。Profile の導入により、JavaEE の全APIではなく、必要なAPIのみを採用したサブセットを定義することができ、結果としてアプリケーションサーバーを軽量化することができます。
-
-JavaEE6 では全APIをカバーする Full Profile と Web アプリケーションの開発に必要な API セットとして Web Profile を定義しています。Web Profileは Servlet や JSP といった Web 関連の技術だけではなく、JPA や JTA といったデータベース接続のための API も含んでいるのが特徴です。
-
-Profile の他にも、Pruning と呼ばれる概念も追加されています。これは古い仕様を廃止していくというものです。JavaEE6 では EJB2 のエンティティBean と JAX-RPC が候補に上がっているようです。
-
-開発容易性 (EoD) の向上は、JavaEE6 の前身である JavaEE5 から取り組まれるようになった課題です。XML などを使った外部設定をできるだけ書かずに済むように、Configuration-by-Exception (必要なな場合のみデフォルト値を上書きする方法) という方針のもと API の策定がなされています。
-
-結果として、JavaEE6 の API にはおびただしい数のアノテーションが定義されています。ブラックボックス化が行き過ぎていて、逆に分かりにくい部分も決して少なくないというきらいがあります。
+JavaEE6 で新たに導入された概念として、Profile があります。Profile の導入により、JavaEE の全 API ではなく、必要な API のみを採用したサブセットを定義することができ、結果としてアプリケーションサーバーを軽量化することができます。
+
+JavaEE6 では全 API をカバーする Full Profile と Web アプリケーションの開発に必要な API セットとして Web Profile を定義しています。Web Profileは Servlet や JSP といった Web 関連の技術だけではなく、JPA や JTA といったデータベース接続のための API も含んでいるのが特徴です。
+
+Pruning と呼ばれる概念も追加されました。これは古く、かつ残す価値が低い仕様を廃止していくというものです。JavaEE6 では EJB2 の Entity Bean と JAX-RPC が候補に上がっているようです。
+
+開発容易性の向上は、JavaEE6 の前身である JavaEE5 から取り組まれるようになった課題です。XML などを使った外部設定をできるだけ書かずに済むように、Configuration-by-Exception (必要なな場合のみデフォルト値を上書きする方法) という方針のもと API の策定がなされています。
+
+EoD 促進の結果として、JavaEE6 の API にはおびただしい数のアノテーションが定義されています。手続き的な API を避けようという動きの結果です。ブラックボックス化が行き過ぎていて、逆に分かりにくい部分も決して少なくないというきらいがあります。
 
 また、同じような機能を提供するアノテーションが複数のコンポーネントで定義されていたりするのも混乱の元です。例えば今回取り上げる CDI の DI 機能も、EJB では `@EJB` という EJB 専用のアノテーションが設けられていたり、JAX-RS では `@Context` という JAX-RS 専用のアノテーションが設けられていたり、といった具合です。
 
@@ -96,6 +96,12 @@
 などが挙げられます。
 
 中・小規模なアプリケーションであっても、高レベルなトランザクション制御 (宣言的トランザクション) にあやかりたい場合など、EJB のお世話になるシーンはそれなりにあると思います。
+
+## なぜ今 JavaEE6 なのか
+
+2013年に JavaEE6 の後継となる JavaEE7 がリリースされました。JavaEE6 の流れを組んだ、新しい仕様です。JavaEE6 では行き届かなかった細かい改善点が数多く見られ、JavaEE7 が使えるのであれば JavaEE7 を選択すべきだと思います。
+
+しかし [Java EE Compatibility](http://www.oracle.com/technetwork/java/javaee/overview/compatibility-jsp-136984.html) を見ればわかるように、JavaEE7 準拠のアプリケーションサーバーは非常に少ないという現状があります (2015/3 現在)。この現状を踏まえ、現実のプロジェクトで JavaEE7 が採用されるのはまだまだ先になりそうであるということで、今回は比較的実装が多い JavaEE6 を取り上げました。
 
 # 使ってみる
 
@@ -185,7 +191,7 @@
 }
 ```
 
-手動の場合、どうにか自力で MailNotifier のインスタンスと、NotificationService のインスタンスを得る必要があります。今回は依存性のルートから new してインスタンス化します。
+手動の場合、どうにか自力で `MailNotifier` のインスタンスと、`NotificationService` のインスタンスを得る必要があります。今回は依存性のルートから new してインスタンス化します。
 
 ```java
 @WebServlet(urlPatterns = { "/di/cdi" })
@@ -206,7 +212,7 @@
 }
 ```
 
-NotificationService のコンストラクタで Notifier への依存性を注入しています。この実装では NotificationService から Notifier への依存性は外部から注入できますが、MyServlet から NotificationService, Notifier への依存性は外部から注入することができません。この程度の規模であれば少しの修正で対応できるでしょうが、規模が大きくなってくると、実装の煩わしさが常について回ります。
+`NotificationService` のコンストラクタで `Notifier` への依存性を注入しています。この実装では `NotificationService` から `Notifier` への依存性は外部から注入できますが、`MyServlet` から `NotificationService`, `Notifier` への依存性は外部から注入することができません。この程度の規模であれば少しの修正で対応できるでしょうが、規模が大きくなってくると、実装の煩わしさが常について回ります。
 
 ## CDI による DI
 
@@ -248,7 +254,7 @@
 
 といったところで、その一つを満たせばよいことになっています。
 
-これ以外は特に設定なども必要ありません。依存性を注入したい場所に `@javax.inject.Inject` アノテーションをつけておけば、アプリケーションサーバー上で稼働する CDI コンテナによって依存関係が解決されます。
+これ以外は特に設定なども必要ありません。依存性を注入したい場所に `@Inject` をつけておけば、アプリケーションサーバー上で稼働する CDI コンテナによって依存関係が解決されます。
 
 ただし CDI を有効にするためのファイルだけ作っておく必要があります。[^1]
 
@@ -256,8 +262,6 @@
 $ touch cditutor/WEB-INF/beans.xml
 ```
 
-[^1]: CDI1.1 (JavaEE7) からは仕様が変わります
-
 ## JSR-330 との関係について
 
 実は CDI の DI 仕様というのは、別の JSR で策定された仕様です。ここまで「CDI の DI」と呼んできた機能は、厳密に言うと JSR-330 (Dependency Injection for Java) という仕様で定義された DI 機能です。CDI の DI 部分は JSR-330 に乗っかっていて、そこにコンテキストやデコレータ、イベントやデプロイの仕様を追加したのが CDI (JSR-299) になります。
@@ -270,26 +274,24 @@
 
 CDI 仕様では以下の機能を提供します:
 
- 1. コンテキスト: JavaEEコンポーネント (Servlet, EJB など) がアプリケー
-    ションのライフサイクル内で明確なスコープを持って存在できるようにする
- 2. 依存性の注入: コンテキストを持つオブジェクトに対して自動的に依存性
-    を注入する
+ 1. オブジェクトの明確なコンテキスト
+ 2. 依存性の注入: コンテキストを持つオブジェクトに対して自動的に依存性を注入する
  3. JavaEE のコンポーネント同士を粗結合に接続し、モジュール化を促進する
  4. EL 式から直接参照できるようにする
- 5. CDI により注入されるオブジェクトをラップする
+ 5. CDI により注入されるオブジェクトのデコレーション
  6. タイプセーフなインターセプタのバインディングを提供する
  7. イベント通知
  8. Servlet API (Web) 向けに定義されたコンテキスト
- 9. ポータブルに拡張可能するための SPI
-
-## コンテキスト/スコープ
-
-JavaEE のコンポーネントの明確なライフサイクル (スコープ) を提供する機能です。CDI のもっとも基本的な機能のひとつです。明確なスコープが設定されたオブジェクトは、
-
- * スコープの開始と終了にあわせて自動的にインスタンス化され、自動的に破
-   棄される
- * 複数のクライアントから同時に参照可能なスコープを持つオブジェクトは、
-   その状態を自動的に共有される
+ 9. CDI を拡張するための SPI
+
+これは JSR-299 の冒頭に箇条書きされているものです。1, 2 の仕様を軸として、デコレータ、インターセプタ、イベント通知などの機能を統合し、EL式や Servlet といった他の仕様との兼ね合いも意識したものになっています。この辺がサードパーティ製の DI コンテナである Spring や Guice とは単純には比較できないところになります (カバーしている領域が違う)。
+
+## コンテキスト
+
+コンテナが管理する JavaBeans の明確なライフサイクル (スコープ) を提供する機能です。CDI のもっとも基本的な機能のひとつです。明確なスコープが設定されたオブジェクトは、
+
+ * スコープの開始と終了にあわせて自動的にインスタンス化され、自動的に破棄される
+ * 複数のクライアントから同時に参照可能なスコープを持つオブジェクトは、その状態を自動的に共有される
 
 CDI 1.0 仕様では 5 つのスコープがあらかじめ定義されています:
 
@@ -301,9 +303,9 @@
 @ConversationScoped | 会話スコープ。任意の長さ
 @Dependent | 依存元のスコープに依存。擬似スコープ
 
-すべてアノテーションで、 `javax.enterprice.context` パッケージに定義されています。
-
-ApplicationScoped, SessionScoped, RequestScoped の動きを見てみます。まずはスコープを指定したクラス (依存される側のクラス) を定義します。
+すべてアノテーションが `javax.enterprice.context` パッケージに定義されています。
+
+`@ApplicationScoped`, `@SessionScoped`, `@RequestScoped` の動きを見てみます。まずはスコープを指定したクラス (依存される側のクラス) を定義します。
 
 ```java
 // Counter.java
@@ -369,9 +371,9 @@
 }
 ```
 
-もっとも大きいスコープである ApplicationScoped から、より狭いスコープである SessionScoped 及び RequestScoped に依存しています。ApplicationScoped なオブジェクトが破棄される前に、より狭いスコープのオブジェクトは生成/破棄が行われることになります。
-
-ApplicationScoped に依存するクラスを定義します。今回も Servlet として定義しています。
+もっとも大きいスコープである `@ApplicationScoped` から、より狭いスコープである `@SessionScoped` 及び `@RequestScoped` に依存しています。`@ApplicationScoped` なオブジェクトが破棄される前に、より狭いスコープのオブジェクトは生成/破棄が行われることになります。
+
+`@ApplicationScoped` に依存するクラスを定義します。今回も Servlet として定義しています。
 
 ```java
 @WebServlet(urlPatterns = { "/lifecycle/scope" })
@@ -397,7 +399,7 @@
 情報:   org.creasys.cditutor.lifecycle.scope.CountWriter@983aab1::destroy (RequestScoped)
 ```
 
-初めてのアクセスなので ApplicationScoped が初期化されました。セッションが開始したので SessionScoped も初期化されています。RequestScoped は初期化され、破棄されていることが分かります。
+初めてのアクセスなので `@ApplicationScoped` が初期化されました。セッションが開始したので `@SessionScoped` も初期化されています。`@RequestScoped` は初期化され、破棄されていることが分かります。
 
 別のブラウザからアクセスしてみます:
 
@@ -407,7 +409,7 @@
 情報:   org.creasys.cditutor.lifecycle.scope.CountWriter@67974cb0::destroy (RequestScoped)
 ```
 
-ApplicationScoped は初期化されていないことが分かります。SessionScoped が初期化されたのは、別ブラウザからのアクセスなので新しいセッションが開始したためです。
+`@ApplicationScoped` は初期化されていないことが分かります。`@SessionScoped` が初期化されたのは、別ブラウザからのアクセスなので新しいセッションが開始したためです。
 
 最初にアクセスしたブラウザからもう一度アクセスしてみます:
 
@@ -416,13 +418,13 @@
 情報:   org.creasys.cditutor.lifecycle.scope.CountWriter@6824a077::destroy (RequestScoped)
 ```
 
-RequestScoped だけが初期化・破棄されています。すでにセッションが開始しているため、SessionScoped は以前に初期化されたものが利用されています。
+`@RequestScoped` だけが初期化・破棄されています。すでにセッションが開始しているため、`@SessionScoped` は以前に初期化されたものが利用されています。
 
 このように、CDI ではスコープの大小関係を意識せずにつなぐことができるようになっています。この機構により、オブジェクトのライフサイクルを単純に考え、そのまま実装に起こすことができます。Web 開発であれば、
 
- * 画面からのリクエストに関連する情報 (入力など): RequestScoped
- * セッションが続く間保持したい情報 (ログイン情報など): SessionScoped
- * ステートレスなロジックなど: ApplicationScoped
+ * 画面からのリクエストに関連する情報 (入力など): `@RequestScoped`
+ * セッションが続く間保持したい情報 (ログイン情報など): `@SessionScoped`
+ * ステートレスなロジッククラス: `@ApplicationScoped`
 
 といった具合にスコープを指定しさえしておけば、あとは CDI がオブジェクトのライフサイクルを管理し、適切に依存性の注入までしてくれるというわけです。
 
@@ -480,7 +482,7 @@
 
 Document が返す生のテキストを整形して返すという想定です。今回の実装では、連続するスペースを 1 つにまとめるという取ってつけたような実装としています。
 
-デコレータを CDI に認識させるには、 *有効化* する必要があります。CDI1.0 では beans.xml の `<decorators>` 要素にエントリを追加することで、デコレータを有効化できます:
+デコレータを CDI に認識させるには、デコレータを *有効化* する必要があります。CDI1.0 では beans.xml の `<decorators>` 要素にエントリを追加することで、デコレータを有効化できます: [^1]
 
 ```xml
 <?xml version="1.0" encoding="UTF-8"?>
@@ -504,7 +506,7 @@
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         PrintWriter pw = resp.getWriter();
-        pw.println(doc.getText());
+        pw.println(doc.getText().replace(" ", "&nbsp;"));
     }
 }
 ```
@@ -521,7 +523,7 @@
 
 ありがちな例として、メソッドの開始・終了ログを出力するインターセプタを定義してみます。
 
-まず、インターセプタを識別するための InterceptorBinding を定義します:
+まず、インターセプタを識別するための `@InterceptorBinding` を定義します:
 
 ```java
 @InterceptorBinding
@@ -557,7 +559,7 @@
 
 `ic.proceed()` が、インターセプトした対象の処理を実行している部分です。他がインターセプタ独自の実装 (ロギング) になります。
 
-インターセプタを利用するには、デコレータ同様、 *有効化* が必要になります。CDI 1.0 では (これまたデコレータと同様) beans.xml の `<interceptors>` 要素にエントリを追加する必要があります。
+インターセプタを利用するには、デコレータ同様、 *有効化* が必要になります。CDI 1.0 では (これまたデコレータと同様) beans.xml の `<interceptors>` 要素にエントリを追加する必要があります: [^1]
 
 ```xml
 <?xml version="1.0" encoding="UTF-8"?>
@@ -615,11 +617,24 @@
 
 ## イベント
 
-CDI 上で動作するモジュール同士でイベント通知するための機能が CDI に用意されています。明示的なリスナーの登録が不要で、通知先は、イベントオブジェクトの型と Qualifier によって判断されます。
+CDI 上で動作するモジュール同士でイベント通知するための機能が CDI に用意されています。明示的なリスナーの登録が不要で、通知先は、イベントオブジェクトの型によって判断されます。
 
 例を見てみます。まず、イベント通知を受ける側の実装です:
 
 ```java
+// LoggedInEvent.java
+public class LoggedInEvent {
+    private final String userId;
+    
+    public LoggedInEvent(String userId) {
+        this.userId = userId;
+    }
+    
+    public String getUserId() {
+        return userId;
+    }
+}
+
 @SessionScoped
 public class CurrentUser implements Serializable {
     private static final long serialVersionUID = 1L;
@@ -627,9 +642,9 @@
     private String userId;
     private boolean admin;
     
-    public void onLoggedIn(@Observes @LoggedIn String userId) {
+    public void onLoggedIn(@Observes LoggedInEvent event) {
         System.out.println("[OBSERVER] thread=" + Thread.currentThread().getId());
-        this.userId = userId;
+        this.userId = event.getUserId();
         this.admin = isAdmin(userId);
     }
     
@@ -647,14 +662,11 @@
 }
 ```
 
-ログイン中のユーザー情報を保持するクラスを @SessionScoped で定義しています。 `onLoggedIn` メソッドがイベント通知を受けるメソッドです。ここではユーザーIDがイベント情報として送信されることを期待しています。
-
-ポイントは
-
- * 仮引数に `@Observes` アノテーションをつけること
- * 必要であれば Qualifier で受け取るイベントを明確にすること
-
-といったところです。
+`LoggedInEvent` はイベントそのものを表現するクラスです。ログインユーザーのユーザーIDを持ちます。
+
+ログイン中のユーザー情報を保持するクラス `CurrentUser` を `@SessionScoped` で定義しています。 `onLoggedIn` メソッドがイベント通知を受けるメソッドです。
+
+ポイントは *仮引数に `@Observes` アノテーションをつけること* です。
 
 次に通知する側です:
 
@@ -662,7 +674,7 @@
 @WebServlet(urlPatterns = "/event")
 public class MyServlet extends HttpServlet {
 
-    @Inject @LoggedIn Event<String> login;
+    @Inject Event<LoggedInEvent> login;
     @Inject CurrentUser user;
 
     @Override
@@ -675,7 +687,7 @@
         }
         else {
             req.getSession(true);
-            login.fire(uid);
+            login.fire(new LoggedInEvent(uid));
             System.out.println("[SENDER] thread=" + Thread.currentThread().getId());
         }
 
@@ -684,34 +696,9 @@
 }
 ```
 
-`login.fire(uid)` の部分がイベント通知を行っているところです。 login は `Event` 型のフィールドで、イベント引数として `String` を指定しています。また `@LoggedIn` アノテーションを付加しているので、 `@Observes @LoggedIn String xxx` という引数を持つメソッドに、イベントが通知されます。
-
-## デプロイ
-
-CDI 仕様には「パッケージングとデプロイ」の章が設けられ、CDI が有効化されたモジュールがアプリケーションサーバーにどのようにデプロイされるかが仕様として決められています。
-
- 1. アプリケーションが開始すると、コンテナは bean discovery し
-   * 定義エラーを検出
-   * デプロイの問題を検出
-   * portable extensions にデプロイライフサイクルに関するイベントを通知
- 2. bean discovery は次のことを決定するプロセス:
-   * アプリケーション内に含まれる beans と bean archive を検出
-   * 有効化されている alternatives, interceptors, decorators を bean archive ごとに検出
-   * 有効化されている decorators, interceptors の順序を決める
-
-bean archive とは:
- * META-INF/beans.xml が存在する library jar, EJB jar, app client jar, ear
- * WEB-INF/beans.xml が存在する war
- * META-INF/beans.xml が存在する classpath ディレクトリ
-
-アプリケーション初期化のライフサイクル:
- * コンテナは CDI 拡張モジュールを検索する
- * bean discovery を開始する前に、BeforeBeanDiscovery イベントを通知する
- * bean discovery を実施する
- * bean discovery が完了すると AfterBeanDiscovery イベントを通知する
- * コンテナはデプロイの問題 (DI の矛盾、あいまいさの検出など) がないか検査
- * 検査が完了したら AfterDeploymentValidation イベントを通知する
- * 初期化完了
+`login.fire(new LoggedInEvent(uid))` の部分がイベント通知を行っているところです。 `login` は `Event` 型のフィールドで、イベント引数として `LoggedInEvent` を指定しています。
+
+`login.fire(...)` により、`@Observes LoggedInEvent xxx` という引数を持つメソッドに、イベントが通知されます。
 
 # DI について、もう少し
 
@@ -719,7 +706,7 @@
 
 ## DI 方法
 
-先の例ではフィールドに @Inject を付加することで DI させました。@Inject はフィールドの他に、メソッド、コンストラクタに付加することができます。
+先の例ではフィールドに `@Inject` を付加することで DI させました。`@Inject` はフィールドの他に、メソッド、コンストラクタに付加することができます。
 
 ```java
 public class NotificationService {
@@ -748,8 +735,7 @@
 
 JSR-299 の 2.2.1 Legal bean types にまとめられています:
 
- * インタフェース、具象クラス、抽象クラス、final が付けられたクラス、
-   final メソッドを持つクラス
+ * インタフェース、具象クラス、抽象クラス、final が付けられたクラス、final メソッドを持つクラス
  * 具体的な型、または型変数でパラメタライズされたクラス
  * 配列
  * プリミティブ型 (対応するラッパー型と同列に扱われる)
@@ -760,7 +746,7 @@
 JSR-299 によれば、「型変数」がこれに該当しないと記載されています。つまりこんなことができません:
 
 ```java
-public class CannotInject<T> {
+public class Foo<T> {
     @Inject
     T obj;
 }
@@ -768,9 +754,9 @@
 
 ## Produces
 
-これまで取り上げてきた @Inject で注入するオブジェクトは、すべてコンテナが直接生成したインスタンスを利用してきました。実際にはファクトリメソッドで生成したインスタンスを利用したい場合もあります。
-
-この要件を満たすのに利用できるのが @Produces です。
+これまで取り上げてきた `@Inject` で注入するオブジェクトは、すべてコンテナが直接生成したインスタンスを利用してきました。実際にはファクトリメソッドで生成したインスタンスを利用したい場合もあります。
+
+この要件を満たすのに利用できるのが `@Produces` です。
 
 ```java
 public class LoggerProduces {
@@ -782,9 +768,9 @@
 }
 ```
 
-Logger を生成する @Produces メソッドを定義しました。
-
-InjectionPoint クラスは、@Inject が付加された場所を表現するオブジェクトです。@Produces が付加されたメソッドの引数として受け取ることができます。
+`Logger` を生成する `@Produces` メソッドを定義しました。
+
+`InjectionPoint` クラスは、`@Inject` が付加された場所を表現するオブジェクトです。`@Produces` が付加されたメソッドの引数として受け取ることができます。
 
 使ってみます:
 
@@ -817,7 +803,7 @@
 
 ## Qualifier
 
-これまで見てきた DI の例は、全て CDI の Typesafe Resolution という仕組みに則って、その依存性が解決されてきました。依存する側とされる側との間で方が矛盾しなければ、その間に依存性を注入するというものです。
+これまで見てきた DI の例は、全て CDI の *Typesafe Resolution* という仕組みに則って、その依存性が解決されてきました。依存する側とされる側との間で型が矛盾しなければ (= 代入可能であれば)、その間に依存性を注入するというものです。
 
 しかしこれだけではカバーできない場合もあります。例えばデータソースが複数の用途で分かれているとして、
 
@@ -835,13 +821,13 @@
 }
 ```
 
-という風に書いていたとします。user と payment は全く別のデータソース (例えば DB が異なる) とします。
+という風に書いていたとします。`user` と `payment` は全く別のデータソース (例えば DB が異なる) とします。
 
 Typesafe Resolution だけでは、 `user` と `payment` には同じインスタンスに依存するものとして解決されてしまい、期待する動作とはなりません。
 
-そもそもこのプログラムはデプロイできません。同じ型に対する @Produces メソッドが複数存在するため、コンテナがどちらのメソッドを使って依存性を解決すればよいかが判断できないためです。
-
-こういった自体を解決するために用意されているのが @Qualifier アノテーションです。Qualifier は基本的にアプリケーションの要件に応じて自分で定義していきます。ここでは @User と @Payment を定義してみます:
+そもそもこのプログラムはデプロイできません。同じ型に対する `@Produces` メソッドが複数存在するため、コンテナがどちらのメソッドを使って依存性を解決すればよいかが判断できないためです。
+
+こういった自体を解決するために用意されているのが `@Qualifier` です。Qualifier は基本的にアプリケーションの要件に応じて自分で定義していきます。ここでは `@User` と `@Payment` を定義してみます:
 
 ```java
 // User.java
@@ -875,7 +861,7 @@
 }
 ```
 
-ファクトリメソッドと注入ポイントそれぞれに @User と @Payment を付加しました。これによってコンテナはどこに何を注入すればよいかを判断できるようになります。
+ファクトリメソッドと注入ポイントそれぞれに `@User` と `@Payment` を付加しました。これによってコンテナはどこに何を注入すればよいかを判断できるようになります。
 
 # クライアントサイドプロキシ
 
@@ -904,7 +890,7 @@
 }
 ```
 
-こんな依存関係を組んでいたとします。Client のインスタンスを複数作ったとしても、Foo のインスタンスは ApplicationScoped なので 1 つしか作られません。また Foo が依存する Bar は呼び出し元のセッションに応じて切り替える必要があります。
+こんな依存関係を組んでいたとします。`Client` のインスタンスを複数作ったとしても、`Foo` のインスタンスは `ApplicationScoped` なので 1 つしか作られません。また `Foo` が依存する `Bar` は呼び出し元のセッションに応じて切り替える必要があります。
 
 ```java
 // セッション1
@@ -936,7 +922,7 @@
 
 ![client-proxy-seq.png](/rambo/static/images/ce0c2aa5-accd-43fd-8806-70cea1fbcc84.png)
 
-ApplicationScoped, SessinoScoped でライフサイクルが明示されたオブジェクトに対する呼び出しは、そのプロキシオブジェクトの呼び出しになります。プロキシ内では呼び出し元や呼び出されたスレッドなどを元に適切なオブジェクトを生成、選択し、処理を移譲します。
+`ApplicationScoped`, `SessinoScoped` でライフサイクルが明示されたオブジェクトに対する呼び出しは、そのプロキシオブジェクトの呼び出しになります。プロキシ内では呼び出し元や呼び出されたスレッドなどを元に適切なオブジェクトを生成、選択し、処理を移譲します。
 
 ライフサイクルの例で出したプログラムを書き換え、クライアントプロキシの存在を確認してみます:
 
@@ -960,11 +946,15 @@
 class org.creasys.cditutor.lifecycle.scope.Counter$Proxy$_$$_WeldClientProxy
 ```
 
-と表示されます。Counter クラスの名前ではなく、実行時に自動生成されたプロキシクラスの名前が出力されています。Weld というのは Glassfish で利用されている CDI 実装です。
+と表示されます。`Counter` クラスの名前ではなく、実行時に自動生成されたプロキシクラスの名前が出力されています。Weld というのは Glassfish で利用されている CDI 実装です。
 
 # まとめ
 
 だらだらと CDI 1.0 の全容を追っかけてきました。大体の雰囲気は掴んでもらえたんじゃないかと思います。
 
+触れなかった仕様がいくつかあります。デプロイに関する仕様、CDI の拡張モジュールを作るための仕様などです。デプロイに関する仕様はデバッグ時には役立つ知識になるでしょうし、CDI の拡張モジュールは独自のスコープを定義するときに関係してきます。
+
 CDI 仕様は、仕様書ページ数こそ 100 ページ程度とさほど多いものではないものの、機能はそれなりに豊富で、かつ他の仕様にまたがっている部分が多々あるため、複雑です。かといって「複雑で使い物にならない!」というものではなく、「DI や Context だけ使おう」といった具合に、分かりやすいところだけでも十分に使いでのある仕様だと思います。
 
+[^1]: CDI1.1 (JavaEE7) からは仕様が変わります
+

nishikawa が 2015-03-28 10:20 に投稿