我的应用程序中有一个奇怪的行为:我使用SessionScopebean(bean a)来保存用户的偏好。在RequestScope中的另一个Bean(Bean B)中,我注入了SessionScope Bean。
Bean B有一个@PostConstruct方法,用于根据Bean a中的值从数据库中检索值列表。当用户更改Bean a中值时,应用程序会感到困惑,而在调用@PostConstruct方法时,它在Bean B中的值不正确。我用日志进行了测试。
我认为所有的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;
}
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重新呈现,并且最后两个日志的顺序不正确,我的应用程序会混淆。
谢谢你的帮助。
@PostConstruct
在调用操作阶段不执行。它是在bean构造之后直接执行的。PostConstruct
应该只用于在bean构造后直接根据注入的依赖关系预初始化一些东西。因为您的bean是请求范围的,而不是会话范围的(或视图范围的),所以它将在每个请求上构建。
您需要在实际操作方法中执行更新/刷新工作,这是您在<h:commandButton>
/<h:commandLink>
中指定的方法。例如
<h:commandButton value="Submit" action="#{bean.submit}" />
带有
public void submit() {
// ...
retrieveAllSubAccount();
}
我还建议将您的bean放在CDI会话范围或JSF视图范围中,这样就不会在每次回发到同一视图时不必要地对其进行重构。