@Named @Sessionscoped的@PostConstruct在单个请求期间多次调用

时间:2014-08-24 13:53:32

标签: jsf cdi

我试图执行一个" helloWorld"学习CDI的项目类型,我有点迷失,我不理解我注意到的行为。

首先,在阅读了参考文档后,我试图从WELD发行版中执行这些示例:http://docs.jboss.org/weld/reference/latest/en-US/html/,第6章

嗯,我不知道为什么,但无论我怎么做,它们都不适合我。所以,我决定"重写"第一个练习,如果我现在可以看到正在运行的应用程序(JBoss EAP),我现在不明白现在的情况:

我的项目:

计算随机数的生成器(ApplicationScoped):

@ApplicationScoped
public class Generator implements Serializable{

    private static final int MAX_NUMBER = 100;

    private java.util.Random random = new java.util.Random(System.currentTimeMillis());

    /**
     * Serializable
     */
    private static final long serialVersionUID = 7388013951586598074L;

    @Produces
    public @MaxNumber int getMaxNumber(){
        return MAX_NUMBER;
    }

    java.util.Random getRandom() {
        return random;
    }

    @Produces
    @Random
    int next() {
        //a number between 1 and 100
        return getRandom().nextInt(MAX_NUMBER - 1) + 1;
    }
}

游戏bean,SessionScoped

@SessionScoped
@Named
public class Game implements Serializable{

    /**
     * Serializable
     */
    private static final long serialVersionUID = 8480529461297926872L;

    /**
     * The real number
     */
    private int number;

    /**
     * The guessed number
     */
    private int guess;

    /**
     * The limit min/max of number could be (updated for each try)
     */
    private int biggest;
    private int smallest;

    /**
     * Remaining guesses
     */
    private int remainingGuesses;

    @Inject
    private @MaxNumber int maxNumber;

    @Inject
    private @Random Instance<Integer> randomNumber;

    public void check(){
        if (guess > number) {
            biggest = guess - 1;
        } else if (guess < number) {
            smallest = guess + 1;
        } else if (guess == number) {
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Correct!"));
        }
        remainingGuesses--;
    }

    @PostConstruct
    public void reset(){
        this.smallest = 0;
        this.guess = 0;
        this.remainingGuesses = 10;
        this.biggest = maxNumber;
        this.number = randomNumber.get();
    }

    public void validateNumberRange(FacesContext context, UIComponent toValidate, Object value) {
        if (remainingGuesses <= 0) {
            FacesMessage message = new FacesMessage("No guesses left!");
            context.addMessage(toValidate.getClientId(context), message);
            ((UIInput) toValidate).setValid(false);
            return;
        }
        int input = (Integer) value;

        if (input < smallest || input > biggest) {
            ((UIInput) toValidate).setValid(false);

            FacesMessage message = new FacesMessage("Invalid guess");
            context.addMessage(toValidate.getClientId(context), message);
        }
    }

    public int getNumber() {
        return number;
    }

    public int getBiggest() {
        return biggest;
    }

    public int getSmallest() {
        return smallest;
    }

    public int getRemainingGuesses() {
        return remainingGuesses;
    }

    public void setRemainingGuesses(int remainingGuesses) {
        this.remainingGuesses = remainingGuesses;
    }

    public int getGuess() {
        return guess;
    }

    public void setGuess(int guess) {
        this.guess = guess;
    }

}

我的两个注释(我把MaxNumber,Random和随机名称相同):

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE,METHOD,FIELD, PARAMETER})
public @interface MaxNumber {

}

我的WEB-INF文件夹中有beans.xml,faces-config和web.xml(前两个文件中只有DOCTYPE,...)

和web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
    <display-name>Try and guess</display-name>
    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Development</param-value>
    </context-param>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>/faces/*</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>faces/index.xhtml</welcome-file>
    </welcome-file-list>
</web-app>

最后,我的index.xhtml:

<!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:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html">


<ui:composition template="/template.xhtml">
    <ui:define name="content">
        <h1>Guess a number...</h1>
        <h:form id="numberGuess">
            <div style="color: red">
                <h:messages id="messages" globalOnly="false" />
                <h:outputText id="Higher" value="Higher!"
                    rendered="#{game.number gt game.guess and game.guess ne 0}" />
                <h:outputText id="Lower" value="Lower!"
                    rendered="#{game.number lt game.guess and game.guess ne 0}" />
            </div>

            <div>
                I'm thinking of a number between <span id="numberGuess:smallest">#{game.smallest}</span>
                and <span id="numberGuess:biggest">#{game.biggest}</span>. You have
                #{game.remainingGuesses} guesses remaining.
            </div>

            <div>
                Your guess:
                <h:inputText id="inputGuess" value="#{game.guess}" required="true"
                    size="3" disabled="#{game.number eq game.guess}"
                    validator="#{game.validateNumberRange}" />
                <h:commandButton id="guessButton" value="Guess"
                    action="#{game.check}" disabled="#{game.number eq game.guess}" />
            </div>
            <div>
                <h:commandButton id="restartButton" value="Reset"
                    action="#{game.reset}" immediate="true" />
            </div>
        </h:form>
    </ui:define>
</ui:composition>
</html>

嗯,现在,发生了什么:

当我尝试访问我的页面时,在显示index.xhtml之前,会多次调用reset方法(标有PostConstruct)。显示的值是预期的值(因为它是我们第一次访问页面时) 我尝试输入一个数字并单击猜测按钮,方法重置被调用几次(我不知道为什么),并且我的方法检查(预期的一次),一次,来完成它的工作。但是再次调用reset方法,显示的页面与开始时的状态相同。 所以问题是: - 为什么在开始时多次调用reset方法? - 为什么要调用reset方法呢?

谢谢你 Cheloute

1 个答案:

答案 0 :(得分:0)

那么, 我认为javax.enterprise.context.SessionScoped和javax.faces.bean.SessionScoped是等价的,但我错了:)

我认为我的Game bean实际上是一个Dependent范围,因为javax.faces.bean.SessionScoped并不像预期的SessionScoped那样处理......