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

时间:2013-11-19 09:27:40

标签: jsf session cluster-computing

我有以下托管bean:

@ApplicationScoped
public class ApplicationBean {
    // ...
}
@SessionScoped
public class SessionBean implements Serializable {

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

    // ...
}

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

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

2 个答案:

答案 0 :(得分:12)

  

当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!)
}

答案 1 :(得分:0)

我正面临类似的问题。

我有一个Quartz调度程序,每x秒运行一次。

Quartz的Job更新了我的应用程序作用域bean中的项目列表。

我使用下面显示的静态方法获取应用程序bean。

当我部署应用程序时,它运行良好,但是当用户输入Web应用程序时,FacesContext.getCurrentInstance()始终返回null。

    public static <T> T getBean(final String beanName, final Class<T> beanClass) {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        T result = null;
        if (facesContext != null) {
            Application application = facesContext.getApplication();
            if (application != null) {
                String expresionBeanName = "#{" + beanName + "}";
                result = application.evaluateExpressionGet(facesContext, expresionBeanName, beanClass);
            }
        }
        return result;
    }

    @ManagedBean
    @ApplicationScoped
    public class ApplicationBean implements Serializable { ... }