当 HTTP 会话在另一个节点上序列化时会发生什么?
所有 HTTP 会话属性也将被序列化,包括会话范围的 JSF 托管 bean。任何不可序列化的 bean 属性都将被跳过。在另一个节点上反序列化期间,您将在所有不可序列化的 bean 属性上遇到NotSerializableException。标记属性transient 将修复该异常,但在反序列化后该属性仍将保留null。
@ManagedProperty 会重新注入它吗?或者它实际上会以某种方式被序列化?
不。它不会被重新注入。如果是@ManagedProperty,您必须手动处理此问题。
一种有点幼稚且容易出错的方法是摆脱 @ManagedProperty 并在 getter 中执行延迟加载(因此,您自己就像代理一样):
private transient ApplicationBean applicationBean;
public ApplicationBean getApplicationBean() {
if (applicationBean == null) {
FacesContext context = FacesContext.getCurrentInstance();
applicationBean = context.getApplication().evaluateExpressionGet(context, "#{applicationBean}", ApplicationBean.class);
}
return applicationBean;
}
并在整个代码中使用 getter,而不是直接引用属性。
更好的方法是使其成为 EJB 或 CDI 托管 bean。它们是完全透明地创建并作为可序列化代理注入的,您无需担心它们的序列化。
因此,要么将其设为 EJB:
import javax.ejb.Singleton;
@Singleton
public class ApplicationBean {
// ...
}
import javax.ejb.EJB;
import.javax.faces.bean.ManagedBean;
import.javax.faces.bean.SessionScoped;
@ManagedBean
@SessionScoped
public class SessionBean implements Serializable {
@EJB
private ApplicationBean applicationBean;
// ... (no setter/getter necessary!)
}
或者,将它们都设为 CDI 托管 bean:
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;
@Named
@ApplicationScoped
public class ApplicationBean {
// ...
}
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;
@Named
@SessionScoped
public class SessionBean implements Serializable {
@Inject
private ApplicationBean applicationBean;
// ... (also here, no setter/getter necessary!)
}