Сбой сеанса JSF и частичное сохранение состояния

Работает на JSF 2.0.9, Weblogic 10.3.4. В настоящее время мы запускаем JSF в нашей производственной среде, но столкнулись с некоторыми проблемами с репликацией сеанса и сбой. Мы используем viewcope для нашего beans, и я гарантировал, что они являются Serializable/transient и что переходные переменные эффективны без гражданства. Однако сбой сеанса не работает. Я провел обширное тестирование и сумел заставить его работать, установив следующие параметры в web.xml

    <context-param>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>client</param-value>
    </context-param>


    <context-param>
        <param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
        <param-value>false</param-value>
    </context-param>

Если я устанавливаю STATE_SAVING_METHOD в server, я получаю исключение viewexpired при отказе. Если я установлен в client с PARTIAL_STATE_SAVING до true, я получаю следующую ошибку:

java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
    at java.util.ArrayList.RangeCheck(ArrayList.java:547)
    at java.util.ArrayList.get(ArrayList.java:322)
    at javax.faces.component.AttachedObjectListHolder.restoreState(AttachedObjectListHolder.java:165)
    at javax.faces.component.UIComponentBase.restoreState(UIComponentBase.java:1433)
    at com.sun.faces.application.view.StateManagementStrategyImpl$1.visit(StateManagementStrategyImpl.java:265)
    at com.sun.faces.component.visit.FullVisitContext.invokeVisitCallback(FullVisitContext.java:151)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1507)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1521)
    at com.sun.faces.component.visit.VisitUtils.doFullNonIteratingVisit(VisitUtils.java:75)
    at com.sun.faces.application.view.StateManagementStrategyImpl.restoreView(StateManagementStrategyImpl.java:282)
    at com.sun.faces.application.StateManagerImpl.restoreView(StateManagerImpl.java:181)
    at com.sun.faces.application.view.ViewHandlingStrategy.restoreView(ViewHandlingStrategy.java:123)
    at com.sun.faces.application.view.FaceletViewHandlingStrategy.restoreView(FaceletViewHandlingStrategy.java:448)
    at com.sun.faces.application.view.MultiViewHandler.restoreView(MultiViewHandler.java:148)
    at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:187)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:111)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:508)
    at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
    at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:301)
    at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:27)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:57)
    at weblogic.servlet.internal.RequestEventsFilter.doFilter(RequestEventsFilter.java:27)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:57)
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3730)
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3696)
    at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
    at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
    at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2273)
    at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2179)
    at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1490)
    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:256)
    at weblogic.work.ExecuteThread.run(ExecuteThread.java:221)

Итак, мои вопросы таковы:

  • Является ли STATE_SAVING_METHOD - client и PARTIAL_STATE_SAVING - false единственным способом, с помощью которого я смогу работать с откатом?
  • Какова стоимость клиентской/ложной комбинации. Является ли эта память/процессор обширной?
  • Является ли это ошибкой, и если она разрешена в 2.1 или 2.2?

Спасибо заранее.

Ответ 1

Я, наконец, получил эту работу, но не без лишних бит и бобов. Во-первых, я добавил следующее в web.xml(да, агрессивно написано неправильно):

    <context-param>
        <param-name>com.sun.faces.enableAgressiveSessionDirtying</param-name>
        <param-value>true</param-value>
    </context-param>

Сохранение клиента теперь перезагружается сервером, а частичное сохранение остается ложным (true просто не работает)

Во-вторых, после реализации HttpSessionAttributeListener я обнаружил, что com.sun.faces.renderkit.ServerSideStateHelper.LogicalViewMap, который содержит состояние в сеансе, только однажды добавил и никогда не удалялся/не добавлялся/не заменялся. Поэтому, хотя он обновлялся на локальном сеансе, эти изменения никогда не повторялись до второго jvm. В документах Weblogic указано, что атрибут setAttribute должен быть вызван для атрибутов сеанса для работы репликации. Чтобы исправить это, я создал слушателя фазы следующим образом:

public class ViewPhaseListener implements PhaseListener {

    public void afterPhase(PhaseEvent phaseEvent)
    {

    }

    public void beforePhase(PhaseEvent phaseEvent)
    {
        HttpServletRequest request = ((HttpServletRequest) phaseEvent.getFacesContext().getExternalContext().getRequest());
        HttpSession session = request.getSession();

        session.setAttribute("com.sun.faces.renderkit.ServerSideStateHelper.LogicalViewMap", session.getAttribute("com.sun.faces.renderkit.ServerSideStateHelper.LogicalViewMap"));

    }

    public PhaseId getPhaseId()
    {
        return PhaseId.RENDER_RESPONSE;
          //To change body of implemented methods use File | Settings | File Templates.
    }
}

Это просто заменяет атрибут после каждого запроса и обеспечивает его повторение. В качестве дополнительной точки я ограничиваю данные, хранящиеся в представлениях, следующим образом:

<context-param>
        <param-name>com.sun.faces.numberOfViewsInSession</param-name>
        <param-value>3</param-value>
    </context-param>

    <context-param>
        <param-name>com.sun.faces.numberOfLogicalViews</param-name>
        <param-value>1</param-value>
    </context-param>

Надеюсь, это поможет любому, у кого есть те же проблемы.

Ответ 2

Репликация сеанса должна обрабатываться балансировщиком нагрузки, поскольку JSF-приложение знает только о контексте в node, к которому он применяется. Таким образом, не обязательно иметь значение STATE_SAVING_METHOD для клиента или сервера.

Звучит так, как будто у вас неправильная конфигурация балансировки нагрузки. Если вы используете HTTP-сервер Apache в качестве прокси-сервера, см. Следующую ссылку для получения дополнительной информации о липкости сеанса:

http://httpd.apache.org/docs/2.2/mod/mod_proxy_balancer.html

Я бы рекомендовал установить ProxySet stickysession = ROUTEID и посмотреть, устраняет ли это проблему.