Challenge Engineer Life !

エンジニア人生を楽しみたい!仕事や趣味で学んだ技術的なことを書いていくブログです。

Java EE 6のDIで理解していなかったこと

今の開発では、メモリの懸念などもあり、なるべく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のインスタンスは別ものになるものと思っていました。

上記を実行すると

f:id:kikutaro777:20130416225408j:plain

となります。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して実行すると

f:id:kikutaro777:20130416225500j:plain

となりました。data2の参照先が別のインスタンスとなったようです。
nullになってるのも「ほぉ」という感じ(InjectじゃなくnewしたのでPostConstructは実行されないってことかなと)

Inject = 自動でやってくれるnew

とか思っていましたが、SessionScopeなインスタンスをInjectする際は違うのですね。。

詳しい方々からすると「何をあたりまえなことを…」という感じかも…ですが、自分のようにJava EE初心者だとこういう基礎的な所で考え違いをしていたり…。精進あるのみ。

にほんブログ村 IT技術ブログへ
にほんブログ村 にほんブログ村 IT技術ブログ Javaへ
にほんブログ村