0

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

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

我认为所有 setter 方法都会在调用应用程序阶段之前更新?

这是一个代码示例:

豆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;
}

豆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 重新呈现视图,并且最后两个日志的顺序不正确,我的应用程序会感到困惑。

谢谢你的帮助。

4

1 回答 1

2

@PostConstruct调用操作阶段不执行。它在bean构建后直接执行。应该只用于在PostConstructbean 构建后直接根据注入的依赖项来预初始化一些东西。因为您的 bean 是请求范围而不是会话范围(或视图范围),所以它将在每个请求上构建。

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

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

public void submit() {
    // ...

    retrieveAllSubAccount();
}

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

于 2012-01-06T13:22:09.223 回答