2011-01-04 9 views
5

同じセッションのSessionScoped CDI Beanのインスタンスが2つあります。私はCDIによって私のために生成されたインスタンスが1つありますが、2つ生成されたという印象を受けました。私はCDIの仕組みを誤解していますか、あるいはバグを見つけましたか?ここでCDI SessionScoped Beanは同じセッションで2つのインスタンスになります

は、Beanコードである:ここで

package org.mycompany.myproject.session; 

import java.io.Serializable; 
import javax.enterprise.context.SessionScoped; 
import javax.faces.context.FacesContext; 
import javax.inject.Named; 
import javax.servlet.http.HttpSession; 

@Named @SessionScoped public class MyBean implements Serializable { 
    private String myField = null; 

    public MyBean() { 
     System.out.println("MyBean constructor called"); 

     FacesContext fc = FacesContext.getCurrentInstance(); 
     HttpSession session = (HttpSession)fc.getExternalContext().getSession(false); 
     String sessionId = session.getId(); 
     System.out.println("Session ID: " + sessionId); 
    } 

    public String getMyField() { 
     return myField; 
    } 

    public void setMyField(String myField) { 
     this.myField = myField; 
    } 
} 

はにfaceletコードです:ここで

<?xml version='1.0' encoding='UTF-8' ?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:f="http://java.sun.com/jsf/core"> 
<f:view contentType="text/html" encoding="UTF-8"> 
    <h:head> 
     <title>Test</title> 
    </h:head> 
    <h:body> 
     <h:form id="form"> 
      <h:inputText value="#{myBean.myField}"/> 
      <h:commandButton value="Submit"/> 
     </h:form> 
    </h:body> 
</f:view> 
</html> 

は、展開してページに移動するから出力さ:GlassFishのを使用して

INFO: Loading application org.mycompany_myproject_war_1.0-SNAPSHOT at /myproject 
INFO: org.mycompany_myproject_war_1.0-SNAPSHOT was successfully deployed in 8,237 milliseconds. 
INFO: MyBean constructor called 
INFO: Session ID: 175355b0e10fe1d0778238bf4634 
INFO: MyBean constructor called 
INFO: Session ID: 175355b0e10fe1d0778238bf4634 

3.0.1

+1

strub:コンストラクタ(初期化子又はブロック)内の非最終的なメソッドを呼び出すは、CDIとの意図しない影響を引き起こします。私はそれ以来、非最終メソッドを使用することは推奨されていません(http://download.oracle.com/javase/tutorial/java/javaOO/initial.html)。 CDIのBeanでListを初期化するために非最終メソッドを使用すると、intitializerは2回呼び出されます。注意:CDIは最終的なメソッドを許可しておらず、Beanが代理可能ではないことを示すランタイム例外がスローされます。 "修正"は、非最終メソッドを呼び出さずに、すべてinitilizerブロックで作業することです。 – Ryan

+0

@PostConstructでアノテーションされたinitメソッドを定義すると、(作成されるBeanの2つのインスタンスにもかかわらず)1回だけ呼び出されることに気付きました。私は、CDIが私のbeanのインスタンスのプールを作成していることを推測しています。私はプールに残っているBeanのインスタンスを現在のHTTPセッションに関連付けることは無意味だと思います。 – Ryan

+1

下記の私の回答を参照してください。第1インスタンスはコンテキストインスタンス、第2インスタンスはプロキシです。 @PostConstructはもちろんコンテキストインスタンスに対してのみ呼び出され、_not_はプロキシに対して呼び出されます。 – struberg

答えて

4

Ryanは、共著者が既に書いているように、そのBeanのプロキシごとに呼び出されます。これは、インターフェイスプロキシ(java.lang.reflect.proxyのようなもの)だけでなく、実際のクラスプロキシを提供するすべてのプロキシメカニズムの標準的な動作です。

また、ctが各シリアル化ごとに呼び出されることも想像してください。したがって、負荷の重いクラスタで作業する場合は、このような多くの時間が表示されます。だから、一般的に豆のために@PostConstructを使用してください。

LieGrue、私は実際に関連する1つによって上記の問題を警告し

+0

お返事ありがとうございます。私はまだあなたのどちらかを理解していません。私は、PostConstructライフサイクルコールバックやpreRenderViewシステムイベントのような、使用のためにBeanを準備する別の方法を知っています。それは素晴らしいです。私の質問は、セッションスコープのBeanの2つのインスタンスが、1人のユーザーがサーバーにヒットした非常に簡単なテストで作成される理由です。負荷分散とクラスタリングを備えた重い負荷のサーバーについては言及していません。複数のプロキシが作成されていますか?もしそうなら、なぜですか?あるいは、各プロキシは、Beanの2つのインスタンスによってバックアップされていますか?もしそうなら、なぜですか? – Ryan

+2

Ryan、私はすべてのプロキシのことが簡単ではないことを知っていますが、2つのコンストラクタの呼び出しを得ることはまったく問題ありません。 第1インスタンスはコンテキストインスタンスそのものです。これはSessionContextに格納されるBeanです。 2番目のインスタンスがプロキシです。デバッガをよく見たり、コンストラクタでクラスをプリントアウトすると、これは実際にあなたのBeanのサブクラスであることがわかります! – struberg

+0

1つはプロキシで、もう1つは実際のBeanです。とった。あなたがCDIを使うときにコンストラクタに入れたものに注意する必要があるようです。 – Ryan

3

プラグインを注入ポイントに使用する際にCDI実装が基底のBeanのデフォルトコンストラクタを呼び出す可能性があります。これはweldとopenwebbeansで使用されるjavassistのデフォルトの動作です。

できるだけデフォルトのコンストラクタで重いものを避け、@PostConstructに移動してください!

+0

OKですが、なぜ2つが作成されていますか? CDIはプールを作成しますか? – Ryan

関連する問題