2013-09-01 51 views
1


我正在阅读Java EE 7教程。在13.12章中,有一个示例应用程序,ajaxguessnumber。我在Glassfish 4中运行这个例子,一切正常。然后我把System.out.println放入bean构造函数中,并且我意识到构造函数在初始页面加载期间被调用两次。为什么会这样,即使对于@SessionScoped bean?
这里是XHTML文件JSF:初始加载页面时调用两次Bean构造函数

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
    <html lang="en" 
     xmlns="http://www.w3.org/1999/xhtml" 
     xmlns:h="http://xmlns.jcp.org/jsf/html" 
     xmlns:f="http://xmlns.jcp.org/jsf/core"> 

    <h:head> 
     <h:outputStylesheet library="css" name="default.css"/> 
     <title>Ajax Guess Number Facelets Application</title> 
    </h:head> 
    <h:body> 
     <h:form id="AjaxGuess"> 
      <h:graphicImage value="#{resource['images:wave.med.gif']}" 
          alt="Duke waving his hand"/> 
      <h2> 
       Hi, my name is Duke. I am thinking of a number from 
       #{dukesNumberBean.minimum} to #{dukesNumberBean.maximum}. 
       Can you guess it? 
      </h2> 
      <p> 
       <h:inputText 
        id="userNo" 
        title="Type a number from 0 to 10:" 
        value="#{userNumberBean.userNumber}"> 
        <f:validateLongRange 
         minimum="#{dukesNumberBean.minimum}" 
         maximum="#{dukesNumberBean.maximum}"/> 
       </h:inputText> 

       <h:commandButton id="submit" value="Submit" > 
        <f:ajax execute="userNo" render="outputGroup" /> 
       </h:commandButton> 
      </p> 
      <p> 
       <h:panelGroup layout="block" id="outputGroup"> 
        <h:outputText id="result" style="color:blue" 
            value="#{userNumberBean.response}" rendered="#{!facesContext.validationFailed}"/> 
        <h:message id="errors1" 
           showSummary="true" 
           showDetail="false" 
           style="color: #d20005; 
           font-family: 'New Century Schoolbook', serif; 
           font-style: oblique; 
           text-decoration: overline" 
           for="userNo"/> 
       </h:panelGroup> 
      </p> 
     </h:form> 
    </h:body> 
</html> 

这里是豆DukesNumberBean

package javaeetutorial.ajaxguessnumber; 

import java.io.Serializable; 
import java.util.Random; 
import javax.enterprise.context.SessionScoped; 
import javax.inject.Named; 


@Named 
@SessionScoped 
public class DukesNumberBean implements Serializable { 

    private Integer randomInt = null; 
    private long maximum = 10; 
    private long minimum = 0; 

    public DukesNumberBean() { 
     System.out.println("Inside DukesNumberBean constructor"); 

     Random randomGR = new Random(); 
     long range = maximum+minimum+1; 
     randomInt = (int) (minimum + randomGR.nextDouble()*range); 
     System.out.println("Duke's number: " + randomInt); 
    } 

    public long getMaximum() { 
     return (this.maximum); 
    } 

    public void setMaximum(long maximum) { 
     this.maximum = maximum; 
    } 

    public long getMinimum() { 
     return (this.minimum); 
    } 

    public void setMinimum(long minimum) { 
     this.minimum = minimum; 
    } 

    /** 
    * @return the randomInt 
    */ 
    public Integer getRandomInt() { 
     return randomInt; 
    } 

    /** 
    * @param randomInt the randomInt to set 
    */ 
    public void setRandomInt(Integer randomInt) { 
     this.randomInt = randomInt; 
    } 

} 

而这里的豆UserNumberBean

package javaeetutorial.ajaxguessnumber; 

import java.io.Serializable; 
import javax.enterprise.context.RequestScoped; 
import javax.inject.Inject; 
import javax.inject.Named; 

@Named 
@RequestScoped 
public class UserNumberBean implements Serializable { 
    @Inject 
    DukesNumberBean dukesNumberBean; 
    private Integer userNumber = null; 
    String response = null; 

    public UserNumberBean() 
    { 
     System.out.println("Inside constructor"); 
    } 

    public void setUserNumber(Integer user_number) { 
     userNumber = user_number; 
    } 

    public Integer getUserNumber() { 
     return userNumber; 
    } 

    public String getResponse() { 
     if ((userNumber != null) && (userNumber.compareTo(dukesNumberBean.getRandomInt()) == 0)) { 
      return "Yay! You got it!"; 
     } 
     if (userNumber == null) { 
      return null; 
     } else { 
      return "Sorry, " + userNumber + " is incorrect."; 
     } 
    } 
} 

任何帮助将非常感激。谢谢。

回答

7

发生这种情况是因为作用域对象和CDI使用代理注入。 CDI首先创建一个代表你的对象的代理,它是你真实对象的子类 - 这是你的构造函数第一次被调用,因为当你实例化一个子类时,总是调用父构造函数。然后CDI实例化你的真实对象以便注入它 - 这是你的构造函数第二次被调用。 更好的方法是将您的初始化登录名放入@PostConstruct方法中。

@PostConstruct 
public void init() {  
    Random randomGR = new Random(); 
    long range = maximum+minimum+1; 
    randomInt = (int) (minimum + randomGR.nextDouble()*range); 
    System.out.println("Duke's number: " + randomInt); 
} 

它只会被调用一次 - 当真实对象被实例化时。有关代理的更多信息,您可以找到here

编辑: 我刚刚发现这个问题的另一种解释 - here

相关问题