skillup

技術ブログ

Java

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

投稿日:2015年7月11日 更新日:

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

Serializableインターフェイス

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

参考リンク

直列化(serialize:シリアライズ)

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

viewScoped

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

ApplicationScoped

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

ConversationScoped

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

参考リンク

1-1) スコープ(Scope)とBeanの生成と破棄

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

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

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

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

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

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

参考書籍

わかりやすいJavaEEウェブシステム入門

-Java
-,

執筆者:


comment

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

関連記事

no image

テストコードの実装

以前、テストコードの大切さを力説しましたが、実際に書いてみると作業の安心度が全く違います。 やはりメソッド単位での確認やデバッグができるのは非常にありがたいです。また時間がたってもテストコードを見るこ …

no image

Fileのアップロード

業務でCSVのアップロードを行っていますが、ファイルになりますと当然文字列ではなく、バイナリ形式のデータが必要になります。 アップロード自体の処理を書いていなかったので、その扱い方についてちょっと書い …

no image

netbeansのJPQL補助機能

JPAでは基本的に生のSQLではなく、JPQLを使って書きます。 SQLでもタイプミスにイライラさせられることは多いのですが、JPQLはもっとですね・・・爆 そこで使えるのがNetbeansの入力補助 …

no image

GlassFishとTomcatの違い

JavaEEの開発を始めてからは基本的にサーバーとしてGlassFishを使っています。 一般的なJavaのサーバーというとTomcatが有名ではないでしょうか。少なくとも私はTomcatしか知りませ …

no image

開発環境と本番での設定ファイル変更

開発と本番で設定ファイル自体(web.xmlなど)はわけると思うのですが、以前はわからず、開発のものと本番のものを手動でわけていました。 Javaでどうやってやるかを調べたところ、pomにかなり便利な …

アーカイブ