Внедрение несериализуемого bean-объекта области применения как управляемое свойство сериализуемого bean-объекта области действия в кластере

У меня есть следующие управляемые бины:

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

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

    // ...
}

Это развертывается в кластер серверов с несколькими узлами. Что произойдет, когда сеанс HTTP будет сериализован на другом узле?

ApplicationBean не сериализуется, потому что не реализует Serializable, Будет ли он повторно введен @ManagedProperty? Или это будет как-то сериализовано?

1 ответ

Что произойдет, когда сеанс HTTP будет сериализован на другом узле?

Все атрибуты сеанса HTTP также будут сериализованы, включая управляемые bean-компоненты JSF. Любые свойства компонента, которые не сериализуются, будут пропущены. Во время десериализации на другом узле вы столкнетесь с NotSerializableException на все свойства бина, которые не сериализуются. Маркировка недвижимости transient исправит это исключение, но свойство все равно останется null после десериализации.


Будет ли он повторно введен @ManagedProperty? Или это будет как-то сериализовано?

Нету. Это не будет повторно введено. Вы должны позаботиться об этом вручную в случае @ManagedProperty,

Один несколько наивный и подверженный ошибкам способ избавиться от @ManagedProperty и выполняем ленивую загрузку в геттере (таким образом, ведите себя как прокси):

private transient ApplicationBean applicationBean;

public ApplicationBean getApplicationBean() {
    if (applicationBean == null) { 
        FacesContext context = FacesContext.getCurrentInstance();
        applicationBean = context.getApplication().evaluateExpressionGet(context, "#{applicationBean}", ApplicationBean.class);
    }

    return applicationBean;
}

и используйте метод получения по всему коду вместо ссылки на свойство напрямую.

Лучший способ - сделать его EJB-компонентом или управляемым компонентом CDI. Они полностью прозрачно созданы и внедрены как сериализуемые прокси, и вам не нужно беспокоиться о сериализации на них.

Таким образом, либо сделайте это 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:

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

У меня аналогичная проблема.

У меня есть планировщик Quartz, который запускается каждые x секунд.

Quartz's Job обновляет список элементов в моем bean-компоненте с областью действия приложения.

Я получаю компонент приложения с помощью статического метода, показанного ниже.

Когда я развертываю приложение, оно работает нормально, но когда пользователь входит в веб-приложение, 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 { ... }
Другие вопросы по тегам