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

リファクタリング

業務で大幅なリファクタリングをする機会があり、その際の注意だったり、気をつけるべきことなどをまとめておきます。 自分用なので自分にしかわからない言葉で書いてある可能性が大きいです。 気になる方は問い合 …

no image

JPAでの算術関数の型&mavenコンパイルプラグイン

本日も小ネタなので2つ同時に扱います。 Contents1 JPAの算術関数2 mavenのコンパイル JPAの算術関数 JPAでは以前、MySQLなどと同じように算術関数を使えると書きました。 参考 …

no image

arquillianでのリソースファイル読み込み

以前、このエントリーでarquillianからライブラリが利用できず、追加のライブラリを導入した、ということを書きました。 実はリソースファイルもそのままですとarquillianからは使用できません …

no image

Javaのコーディングルール

私自身、Javaで仕事をするようになってから3ヶ月ちょっとがたちました。 もともとPHPで仕事はしていましたが、我流でやっていたこともあり、コーディングのルールとかがいい加減だったんですよね・・ ボス …

no image

jenkinsのオートデプロイ

久々にJavaやりました。 Contents1 やりたいこと2 ハマりポイント2.1 Antでのjobの設定2.2 jenkinsでビルドできない2.3 jenkinsのオートデプロイ2.4 SSHで …