今の開発では、メモリの懸念などもあり、なるべくSessionScopeなBackingBeanを利用しないようにしています。かといって完全に取り除けるものでもないので、一部は当然使っていますが。
で、今日はこのSessionScopeで、基礎的な所をちゃんと理解していなかったなぁ…と結構ショックに思うことがあったので備忘としてまとめようかと…。
いかにも素人ちっくな恥ずかしい内容、かつ、まだ色々理解できていないんじゃないか…という不安もあるので「違うよ!」「おかしいよ!」とか突っ込みあればお願いします(^^;
まず、結論から書くと
SessionScopeの(今回はCDI)管理対象BeanをInjectしたとき、同一セッション下であれば、以降のInjectでは同じインスタンスが注入される
ことをわかっていませんでした。なんか上手く説明できていないので、具体例を書くと。
以下のようなSessionScopedのBackingBeanを定義して
package jp.co.hoge.cdiconfirmation;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
@Named(value = "sessionScoped")
@SessionScoped
public class SessionScopedData implements Serializable{
private String test;
@PostConstruct
public void init(){
test = "キープしてる?";
}
}
さらにこいつを別のBackingBeanでInjectします。こっちはRequestScoped。
package jp.co.hoge.cdiconfirmation;
import javax.annotation.PostConstruct;
import javax.inject.Named;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
@Named(value = "indexBean")
@RequestScoped
public class IndexBean {
@Inject
private SessionScopedData data1;
@Inject
private SessionScopedData data2;
private String output;
@PostConstruct
public void init(){
System.out.println(data1.getTest());
System.out.println(data2.getTest());
data1.setTest("どうなる?");
System.out.println(data1.getTest());
System.out.println(data2.getTest());
}
}
自分は今まで、Inject=明示しないnewのようなもの、と理解していたので、上記定義だとdata1とdata2のインスタンスは別ものになるものと思っていました。
上記を実行すると
となります。data1のインスタンスにだけ「どうなる?」をセットしたのですが、data2にも反映されています。というわけで、data1、data2の変数ともに参照先のインスタンスは同じです。
知らなかった… orz
で、1行だけ加えて
package jp.co.hoge.cdiconfirmation;
import javax.annotation.PostConstruct;
import javax.inject.Named;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
@Named(value = "indexBean")
@RequestScoped
public class IndexBean {
@Inject
private SessionScopedData data1;
@Inject
private SessionScopedData data2;
private String output;
@PostConstruct
public void init(){
System.out.println(data1.getTest());
System.out.println(data2.getTest());
data2 = new SessionScopedData();
data1.setTest("どうなる?");
System.out.println(data1.getTest());
System.out.println(data2.getTest());
}
}
として、data2を明示的にnewして実行すると
となりました。data2の参照先が別のインスタンスとなったようです。
nullになってるのも「ほぉ」という感じ(InjectじゃなくnewしたのでPostConstructは実行されないってことかなと)
Inject = 自動でやってくれるnew
とか思っていましたが、SessionScopeなインスタンスをInjectする際は違うのですね。。
詳しい方々からすると「何をあたりまえなことを…」という感じかも…ですが、自分のようにJava EE初心者だとこういう基礎的な所で考え違いをしていたり…。精進あるのみ。