【问题标题】:@PostConstruct called before other SessionScoped Bean updated in JSF2 / CDI?@PostConstruct 在 JSF2 / CDI 中更新其他 SessionScoped Bean 之前调用?
【发布时间】:2012-02-04 05:05:16
【问题描述】:

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

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

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

这是一个代码示例:

豆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 重新呈现,最后两个日志的顺序不正确,我的应用程序迷糊了。

感谢您的帮助。

【问题讨论】:

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


    【解决方案1】:

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

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

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

    public void submit() {
        // ...
    
        retrieveAllSubAccount();
    }
    

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

    【讨论】:

    • 感谢 BalusC。我猜到了,并从该方法中删除了 @PostConstruct 并从 getter 中调用它以作为快速解决方法。这现在有效。实际上我是通过一个 maven 原型得到的,并且会告诉 jboss 的人不推荐这样做。
    • 不,@PostConstruct 在那里很好。你只是误解了它的用途。它是在 bean 构建后直接预初始化的东西。在每个 HTTP 请求上构建一个请求范围的 bean。这都是规范。如果您想调用表单提交操作(例如,保存已编辑的项目并重新加载列表以进行显示),您需要在为此指定的操作方法中完成该工作。
    猜你喜欢
    • 1970-01-01
    • 2012-03-09
    • 1970-01-01
    • 1970-01-01
    • 2020-03-15
    • 2013-05-23
    • 2015-06-01
    • 2019-08-04
    相关资源
    最近更新 更多