将非可序列化应用程序作用域bean注入集群中可序列化会话作用域bean的托管属性

use*_*066 13 session jsf cluster-computing

我有以下托管bean:

@ApplicationScoped
public class ApplicationBean {
    // ...
}
Run Code Online (Sandbox Code Playgroud)
@SessionScoped
public class SessionBean implements Serializable {

    @ManagedProperty("#{applicationBean}")
    private ApplicationBean applicationBean;

    // ...
}
Run Code Online (Sandbox Code Playgroud)

这将部署到具有多个节点的服务器群集.当HTTP会话在另一个节点上序列化时会发生什么?

ApplicationBean未序列化,因为它没有实现Serializable.它会被重新注入@ManagedProperty吗?或者它会以某种方式实际序列化?

Bal*_*usC 12

当HTTP会话在另一个节点上序列化时会发生什么?

所有HTTP会话属性也将被序列化,包括会话范围的JSF托管bean.将跳过任何不可序列化的bean属性.在另一个节点上反序列化期间,您将面对NotSerializableException所有不可序列化的bean属性.标记属性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;
}
Run Code Online (Sandbox Code Playgroud)

并在整个代码中使用getter,而不是直接引用属性.

更好的方法是使其成为EJB或CDI托管bean.它们完全透明地创建并作为可序列化代理注入,您永远不必担心它们的序列化.

因此,要么使它成为EJB:

import javax.ejb.Singleton;

@Singleton
public class ApplicationBean {
    // ...
}
Run Code Online (Sandbox Code Playgroud)
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!)
}
Run Code Online (Sandbox Code Playgroud)

或者,将它们作为CDI托管bean:

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;

@Named
@ApplicationScoped
public class ApplicationBean {
    // ...
}
Run Code Online (Sandbox Code Playgroud)
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!)
}
Run Code Online (Sandbox Code Playgroud)