読者です 読者をやめる 読者になる 読者になる

Challenge Java EE !

Java EEを中心に趣味や仕事における開発メモを書いています。

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

Inject CDI Java EE 6

今の開発では、メモリの懸念などもあり、なるべく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へ
にほんブログ村