今の開発では、メモリの懸念などもあり、なるべく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 = "キープしてる?"; } //testのsetter getterを省略 }
さらにこいつを別の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()); } // outputのsetter getterは省略 // outputはBackingBeanを起動するためにViewが参照してる変数 }
自分は今まで、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する data2 = new SessionScopedData(); data1.setTest("どうなる?"); System.out.println(data1.getTest()); System.out.println(data2.getTest()); } // outputのsetter getterは省略 // outputはBackingBeanを起動するためにViewが参照してる変数 }
として、data2を明示的にnewして実行すると
となりました。data2の参照先が別のインスタンスとなったようです。
nullになってるのも「ほぉ」という感じ(InjectじゃなくnewしたのでPostConstructは実行されないってことかなと)
Inject = 自動でやってくれるnew
とか思っていましたが、SessionScopeなインスタンスをInjectする際は違うのですね。。
詳しい方々からすると「何をあたりまえなことを…」という感じかも…ですが、自分のようにJava EE初心者だとこういう基礎的な所で考え違いをしていたり…。精進あるのみ。