skillup

技術ブログ

Java

スコープアノテーションとCDIについて

投稿日:

JavaEEで個人的に鬼門がCDIとスコープだと思っています。

ここが少しずつ分かりかけてきたんでメモします。

まずJavaEEでは変数の生存期間をアノテーションで定義します。

これがなかなか分かりにくく、慣れるまで時間がかかりました。

ちょっと簡単な例で見ていきましょう。

スコープアノテーション

サンプル

counter

上記のようなボタンを押したらカウントアップするようなプログラムを作るとします。

ファイル構成は単純化するために画面側(counter.xhtml)、プログラム側(SampleBean.java)にともに1つとします。

画面側のファイルcounter.xhtmlについては常に下記のものとします。

プロパティの表示とカウントアップのメソッドのみにします。

外部ファイルは使わず変数のみでこれを実装したいと思います。

@RequestScoped

次にプログラムのほうを見ていきましょう。

リクエストスコープの場合、1回の通信の間のみ変数を保存します。

そのためボタンを押して表示するまでしか変数(正確にはSampleBean)は生きていません。

  1. ボタンを押す
  2. SampleBeanが生成される
  3. ロジックが処理される
  4. 値がレンダリングされる
  5. SampleBeanが破棄される

という流れになるのでカウンタは常に1のままです。(上のサイクルは完全に正確ではないと思いますが、おおまかなイメージです。)

@SessionScoped

次にセッションビーンです。SampleBeanを若干書き換えます。

この場合、ボタンを押すたびにカウンターが上がります。

この場合、流れは下記のようになります。

  1. すでにSampleBeanを生成されている
  2. ボタンを押す
  3. ロジックが処理される
  4. 値がレンダリングされる
  5. セッションが切れた時点でSampleBeanが破棄される

リクエストスコープとちがい、セッションスコープはglassfishがあらかじめ、オブジェクトを生成します。

なので、一定期間(セッションが有効な間は)、値が生存します。

スコープアノテーションで注意すること

importの種類

スコープアノテーションですがimportが複数あるようなので正確なものを選びましょう。そうしないと動きません。下記がそれぞれ正常なスコープアノテーションのimoportです。

javax.enterprise.context.RequestScoped

javax.enterprise.context.SessionScoped

参考リンク

http://rainwont.hatenablog.com/entry/2015/07/08/143203

Serializableインターフェイス

なお、リクエストではなくセッションのようにデータを保存する場合、シリアライズという処理を行います。これを忘れるとそもそもビルドに失敗するので注意しましょう。

参考リンク

http://www.ne.jp/asahi/hishidama/home/tech/java/serial.html

ちなみにスコープはリクエストとセッションではなく、下記のように数種類あります。

viewScoped

リクエストにより表示されたJSFが他の画面に切り替わるまでは値が生存します。今回のカウンターの例でいうと値が残ります。

ApplicationScoped

ウェブアプリケーションが実行されている間は値が残ります。

ConversationScoped

1回以上のリクエストの間で開始と終了をプログラマが明確に定義できます。

参考リンク

https://sites.google.com/site/javar4java/contexts-and-dependency-injection-cdi/scope

なお、当然のことながら不要に値の生存期間を増やすことは

  • メモリの圧迫
  • バグの温床

になりますので、できる限り狭くすることが大切です。

CDIという考え方

ManagedBeanについて説明した後で同時にCDIについても理解しておきたいと思います。

まずサンプルから見ていきましょう。

上記のようなカウンターですが、プログラムをSampleBean.javaのみでなく、

SampleBean.java

Counter.javaの2種類にし、

カウントアップに関してはCounter.javaで行うこととします。

ソース

SampleBean.java

Counter.java

このプログラムを動かすとクリックするごとにカウントアップします。

これはSampleBean.javaがリクエストスコープですが、Counter.javaがセッションスコープなので、値が保存されているためです。

CDI(Context and Dependency Injection)の定義

CDIの定義ですがいろんなところで見聞きしたのですがようわかりませんでした・・・

今では簡単に下記のような解釈をしております。

  • new演算子を使わずにオブジェクトを取得する仕組みであり、生成や破棄の手間がいらない(=正確にはコンテナ(この場合はglassfish)が管理するのでプログラマが管理しなくてよい。)
  • 他のオブジェクトを使用する場合は@Injectというアノテーションを付与するだけでそのオブジェクトが使用できる。

上記の例などがそうですが、Counterオブジェクトに関してnewを使用せずとも、@Injectを使用するだけで使えてしまいます。

インスタンスの生成、破棄などはプログラマ側がしてしなくてよいのです。

ちなみにこのようにして管理されたオブジェクトをCDIビーンと呼びます。

今になってようやくメリットが理解でき始めました(爆)

ちなみにManagedBeanもオブジェクトの生成や破棄をしていないのに、使用できたのはこのCDIの特性を持っているからです。

CDIの条件

このように便利なCDIですが、どんなクラスでもなれるというわけではありません。

CDIとはコンテナがインスタンスを生成することです。

なので、インスタンスが生成できなければCDIビーンにはなれません。これはいわゆる通常のクラスといっしょなので

  • 具象クラスであること
  • 引数なしのディフォルトコンストラクタをもつこと
  • static付きのインナークラスでないこと

という条件が必要になってきます。

CDIのスコープ

CDIのスコープもアノテーションを付与して判断します。アノテーションの種類はさきほど紹介したものといっしょですが、ViewScopedはJSFで定義されているものなので、通常のCDIビーンで定義はできないようです。

また呼び出し側のスコープ(この場合でいうとSampleBean.java)に依存するという@Dependentというスコープも存在します。

CDIって聞いたときはわけがわからんかったんですが、アプリを実際に作りつつようやくメリットが理解できてきました。

ちなみに今回は下記書籍のサンプルを参考にしました。

結構前に読んだ時はよくわからなかったんですが、今読んでみると大変すっきりしました。

参考書籍

http://www.amazon.co.jp/dp/4798042161

 

 

-Java
-,

執筆者:


comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

関連記事

no image

Mapの使い方

Javaに限らずプログラミングで最も大切になるのは配列の処理でしょう。 Javaですと、PHPのような連想配列の代わりにMapを使用します。 Contents1 Mapとは?1.1 Mapのインスタン …

no image

try-with-resourceの使い方

先日ファイル入出力の処理をいろいろと書いていたところ、例外処理について社長からアドバイスをいただきました。 Contents1 ファイルの入出力について2 try-with-resource3 参考リ …

no image

mavenでJavadoc出力

Netbeansでプロジェクトから右クリックでjavadocの生成はできますが、実はmavenでビルドするときにJavadocを生成できます。 ただ出力するだけではなくてパラーメータをいろいろとセット …

no image

入出力操作

Javaの出力処理について書きます。 下記リンクが非常に詳しかったので、これをもとにまとめてみたんですが、咀嚼できてないっぽい・・・・ もう1~2度修正がひつようかも。 http://www.arti …

no image

新アプリの本番環境デプロイについて

新しく作ったWEBアプリを本番配置しようとしたんですが、何度もやっているはずの処理がいざやろうとするといろいろと手間取ってしまい、1時間近くかかりました。 容量悪いなーと思いつつ、こういった行為はなる …