入社式も終えて数か月後には新人さんが入ってきたりする可能性もあるのですが、新人さんの素朴な質問にハッとすることがちょくちょくあります(^^;
質問に上手く答えられず、あー、意外と自分もちゃんと理解してないなぁ、とか…。
先日、新人さんではないですが後輩(Java EE6開発担当ではない子)から
「今やってるJava EE6開発でのセッション管理っていうか、画面情報の記憶とかってどんな仕組みで管理してるですか?」
と聞かれ、どう答えようか迷いました。
その子はもともとASP.NETのWebForm開発とかをメインにしていたので、主にSession.Contents("key") = value;みたいなのをイメージしていたりして。
「アノテーションっていうC#の属性(Attribtue)みたいなのがあって、それで宣言したスコープによってJava EE側が上手いことやってくれてるんだよね…」
みたいな回答の後に、具体例をみせたりしたんですが、何ともわかりにくいような…(-_-;
あとJSFとCDIの管理対象Beanの違いとか、うー、みたいな。
こういう説明がちゃんとできない=ちゃんと理解してないんじゃないの>自分、みたいな流れになってスコープを色々確認してみようと思いました(^^;
今の開発ではCDI管理対象Beanをメインにしているので、本当はそっちでやりたいのですが、まずはJSF管理対象Beanでやっています。
JSF2.0のスコープ種類
主に利用するのは4種類だと思いますが、トータルには6種類あるんですね(^^;
- @ApplicationScoped
- @SessionScoped
- @ViewScoped
- @RequestScoped
- @CustomScoped
- @NoneScoped
CustomScopedとNoneScopedはあまり認識がなかったです…。以下サイトより。
作ってみたもの
ボタンを押すとカウントアップする、という単純なWebで動きを確認してみました。
ボタンはページを読み直しするものと、Ajaxで部分更新する2種類設けてます。
JSFのViewはこんな感じで、pタグはPrimeFacesのボタン(Ajax=true)のものです。
<h:form id="reqCntFrm">
<h:outputText id="reqCnt" value="#{requestScopedCounterBean.count}" />
<h:commandButton value="カウントアップ" actionListener="#{requestScopedCounterBean.countUp()}"
action="requestScopedCounter.xhtml" />
<p:commandButton value="カウントアップ" actionListener="#{requestScopedCounterBean.countUp()}"
ajax="true"
update=":reqCntFrm:reqCnt" />
</h:form>
コードも単純でコンストラクタとsetter/getter、カウントアップするメソッドがあるだけです。スコープに合わせて4つ(request,view,session,application)作りました。
package jp.co.hoge.sessionconfirmation;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
@ManagedBean(name = "requestScopedCounterBean")
@RequestScoped
public class RequestScopedCounterBean implements Serializable{
private int count;
@PostConstruct
public void init(){
count = 0;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public void countUp(){
count++;
}
}
他3つは宣言が
@ManagedBean(name = "viewScopedCounterBean")
@ViewScoped
public class ViewScopedCounterBean implements Serializable {
@ManagedBean(name = "sessionScopedCounterBean")
@SessionScoped
public class SessionScopedCounterBean implements Serializable {
@ManagedBean(name = "appScopedCounterBean")
@ApplicationScoped
public class ApplicationScopedCounterBean implements Serializable{
と違うくらいです。
RequestScoped
まずは一番シンプルなRequestScopedから動かします。
actionListenerでカウントアップされて1となりますが、1回のHTTPリクエストが終わると破棄されるので、再度アクセスしてもカウンタは進みません。どちらのボタンでも同じです。
ViewScoped
次にViewScopedで試します。
まず、画面更新するボタンを押下するとカウントは0から進みません。
actionListenerでカウントアップするも、画面読み直しによりビューが変わるためinitで初期化されてます。
ajax=trueにした部分更新では、ビューとしては同じため、カウントが進みます。
ちなみに新規タブを追加して、URLをコピペすると、セッションは同じでもビューが違うため、新しいカウントで始まります。
SessionScoped
次にSessionScopedを試します。
これはページ読み直し、ajax部分更新、どちらのボタンでもカウントアップします。
さらに新規にタブを追加して、URLをコピペしてもセッションが同じであるためカウントはいきています。
ただし、別のブラウザ立ち上げてセッションが違うような場合は新たなカウントとなります。
ApplicationScoped
アプリケーション全体でキープされるので、ボタンはどちらでもカウントアップするし
タブを追加してもカウントはキープされているし
別のブラウザで立ち上げても、カウントはキープされ、そのままカウントアップも可能です。
CDIで試さなきゃな(^^;