@PostConstruct在JSF2 / CDI中更新的其他SessionScoped Bean之前调用了吗?

时间:2012-01-06 13:12:15

标签: jsf-2 java-ee-6 cdi postconstruct session-scope

我的应用中有一个奇怪的行为: 我使用SessionScope bean(Bean A)来保存用户首选项。在我在RequestScope中的另一个Bean(Bean B)中,我注入了SessionScope bean。

Bean B有一个@PostConstruct方法,用于根据Bean A中的值从数据库中检索值列表。当用户更改Bean A中的值并且Bean B中的值不正确时,应用程序会感到困惑。调用@PostConstruct方法的时间。我用日志测试了它。

我认为所有的setter方法都会在Invoke Application Phase之前更新?

以下是代码示例:

Bean A:

@Named
@SessionScoped
public class SessionBean implements Serializable {
private static final long serialVersionUID = -4214048619877179708L;

@Inject private Logger log;
private BankAccount selectedBankAccount;

public BankAccount getSelectedBankAccount() {
    return selectedBankAccount;
}

public void setSelectedBankAccount(BankAccount selectedBankAccount) {
    log.info("ba: " + selectedBankAccount);
    this.selectedBankAccount = selectedBankAccount;
}

Bean B:

@RequestScoped
public class SubAccountListProducer {
    @Inject private SessionBean sessionBean;
    @Inject private EntityManager em;

@PostConstruct
public void retrieveAllSubAccount() {
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<SubAccount> criteria = cb.createQuery(SubAccount.class);
    Root<SubAccount> account = criteria.from(SubAccount.class);
    log.info("retrieveAllSubAccount: " + sessionBean.getSelectedBankAccount());
    criteria.select(account).where(cb.equal(account.get("bankAccount"), sessionBean.getSelectedBankAccount()));
    criteria.select(account).orderBy(cb.desc(account.get("name")));
    entityList = em.createQuery(criteria).getResultList();
}

示例日志:

ba: BankAccount [accountId=123456789, bankName=Ing DiBa, blz=50010517]
retrieveAllSubAccount: BankAccount [accountId=123456789, bankName=Ing DiBa, blz=50010517]
retrieveAllSubAccount: BankAccount [accountId=123456789, bankName=Ing DiBa, blz=50010517]
ba: BankAccount [accountId=987654321, bankName=Barclaycard Barclays Bank, blz=20130600]

正如您所看到的......前两个日志是正确的...如果用户更改首选项(更新SessionBean),将使用JSF重新呈现视图,并且最后两个日志的顺序不正确并且我的应用程序感到困惑。

感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

在调用操作阶段期间不执行@PostConstruct。它在bean构造后直接执行。 PostConstruct只能用于在bean构造之后直接根据注入的依赖关系预先初始化一些东西。因为您的bean是请求作用域而不是会话作用域(或视图作用域),所以它将在每个请求上构建。

您需要在实际操作方法中执行更新/刷新作业,这是您在<h:commandButton> / <h:commandLink>中指定的方法。 E.g。

<h:commandButton value="Submit" action="#{bean.submit}" />

public void submit() {
    // ...

    retrieveAllSubAccount();
}

我还建议将你的bean放在CDI会话范围或JSF视图范围内,这样就不会在每次回发时不必要地重建到同一个视图。