JSF view получает перестроение при каждом запросе ajax

У меня проблемы с производительностью в моих запросах ajax JSF/RichFaces/Facelets и из того, что я могу сказать, потому что все дерево компонентов перестраивается при каждом запросе ajax. Это происходит, даже если я использую ajaxSingle=true, оборачиваю разделы в a4j:region, объявляю один раздел для повторного рендеринга или ни одного вообще. Наша страница - это динамическая страница с множеством вложенных уровней. Страница может содержать около 800-900 полей (inputText, расширенные календари, selectOneMenus и т. Д.). Время начальной загрузки является проблемой, но я понимаю эту проблему, это много полей. Как только у нас будет время первоначальной сборки / рендеринга, мы разработали все остальные действия как ajax и будем только повторять то, что нужно. В журналах отладки Facelet я вижу такие сообщения при любом вызове ajax:

2011-08-24 22:19:03,054 DEBUG [facelets.viewhandler] (http-0.0.0.0-8080-2) Took
24445ms to build view: /oconsole/appfile.xhtml
2011-08-24 22:19:09,377 DEBUG [facelets.viewhandler] (http-0.0.0.0-8080-2) Took
6323ms to render view: /oconsole/appfile.xhtml

Я не уверен, что что-то, что мы делаем, вызывает перестройку всего дерева компонентов, или facelets определяет эту потребность по какой-то причине (устаревший кеш?). Вот наш стек: JBoss 5.1 JSF 1.2 RichFaces. 3.3.3. Окончательный Facelets 1.1.15 Шов 2.1.2

Я попытался добавить некоторые параметры контекста, чтобы посмотреть, помогут ли они, но они ничего не сделали: facelets.BUILD_BEFORE_RESTORE = false facelets.REFRESH_PERIOD = -1 или 5 (как в 5 мин)

Можно ли как-то сказать, правильно ли кэшируются наши представления? Мы не заботимся о методе сохранения состояния, поэтому я считаю, что по умолчанию используется серверная сторона. Все наши запросы происходят в рамках длительных разговоров. Я не был уверен, что это играет роль, так как я думал, что представления кэшируются на уровне сеанса? Любая помощь будет принята с благодарностью, спасибо.

Обновить после дополнительной отладки:

AjaxViewHandler (который имеет переменную-член FaceletsViewHandler) имеет набор developmentMode=true. Я не уверен, что это приводит к тому, что лицевые грани не кэшируют какие-либо представления, поэтому любые изменения будут обновляться во время циклов разработки...?? Было очень трудно найти какую-либо информацию о кешировании представлений /JSF, а также о поведении и управлении им. Кроме того, когда я добавлю параметр конфигурации:

<context-param>
<param-name>facelets.DEVELOPMENT</param-name>
<param-value>false</param-value>
</context-param>

Это не взял! В отладчике я все еще вижу истинное множество. Так как у нас много подпредставлений, я также попробовал com.sun.faces.numberOfLogicalViews и com.sun.faces.numberOfViewsInSession до 1000 с 15(по умолчанию), и это не имело никакого эффекта.

Я также безуспешно пытался перейти на сохранение состояния на стороне клиента. Кончаются идеи.... надеюсь, кто-то может помочь....

Кажется, Seam 2.1 автоматически инициализирует RichFaces, и я не уверен, что это как-то связано с этим.....

2 ответа

Как и в случае любой проблемы с производительностью, профилировщик может помочь в поиске узких мест. (Да, вы знаете, что это фаза restore_view, но не там, где фаза restore_view).

Тем не менее, фаза восстановления представления действительно восстанавливает весь вид, а не только части, которые будут обработаны или обработаны. Цитируем документацию по меткам библиотеки RichFaces:

process: Id ['s] (в формате вызова UIComponent.findComponent()) компонентов, обработанных на этапах 2-5 в случае AjaxRequest, вызванного этим компонентом. Может быть одним идентификатором, разделенным запятыми списком идентификаторов или выражением EL с массивом или коллекцией

RESTORE_VIEW - фаза 1. Также:

reRender: Id ['s] (в формате вызова UIComponent.findComponent()) компонентов, отображаемых в случае AjaxRequest, вызванного этим компонентом. Может быть одним идентификатором, разделенным запятыми списком идентификаторов или выражением EL с массивом или коллекцией

Более того, я не уверен, что UIComponent.findComponent () реализован с использованием более подходящей структуры данных, чем дерево компонентов. (Поиск чего-либо в дереве компонентов сводится к линейному поиску...).

Я наблюдал подобные эффекты с JSF 2.0 (Мохарра). Мой вывод состоял в том, что представления не должны содержать более пары дюжин компонентов UIC, независимо от того, представлены ли они. (Иными словами, AJAX не подходит для навигации по страницам.) Мы стремимся сохранять небольшие размеры представлений, включая только те компоненты, которые в данный момент видимы в представлении, и переключать представления, если появляется много новых компонентов. То есть вместо одного представления с 10 вкладками по 30 компонентов в каждом у нас будет 10 представлений, каждое из которых будет содержать только содержимое одной вкладки. Недостаток этого подхода заключается в том, что компоненты переключаются при переключении вкладок, в результате чего любое состояние, не сохраняемое в компонентах поддержки, теряется.

Я не утверждаю, что это хорошее решение. Увы, это был лучший вариант, который я нашел, изучив это пару недель назад. Я был бы счастлив, если бы мне показали лучший вариант.

Редактировать Когда я говорю восстановить, я имею в виду ViewHandler.restoreView(), который вызывал как для начального запроса get, так и для обратной передачи. Неверно говорить, что restoreView будет просто использовать существующее представление как есть. Например, спецификации JSF 2.0 в разделе 7.6.2.7: ]

restoreView() Метод должен выполнять следующие обязанности:

Все реализации должны:

  • Если viewId не может быть идентифицирован, вернуть null,
  • Позвоните restoreView() метод связанных StateManager минуя FacesContext экземпляр для текущего запроса и рассчитанный viewId, и вернуть возвращенный UIViewRoot, который может быть null,

и в разделе 7.7.2:

Реализации JSF поддерживают два основных механизма для сохранения состояния, основанные на значении параметра инициализации javax.faces.STATE_SAVING_METHOD (см. Раздел 11.1.3 "Параметры конфигурации приложения"). Возможные значения этого параметра дают общее представление об используемом подходе, позволяя реализациям JSF вводить новшества в технических деталях:

  • клиент - [...]
  • сервер - заставьте сохраненное состояние быть сохраненным на сервере между запросами. Реализации, которые хотят разрешить переключение своего сохраненного состояния на другой экземпляр контейнера, должны учитывать это при реализации своей стратегии сохранения состояния на стороне сервера. Реализация по умолчанию Сериализует представление как в режиме клиента, так и в режиме сервера. В режиме сервера это сериализованное представление сохраняется в сеансе, и уникальный ключ для получения представления отправляется клиенту. Сохраняя сериализованное представление в сеансе, отработка отказа может происходить с использованием обычных механизмов, предоставляемых контейнером.

Иными словами, поддержка AJAX, добавленная в JSF (как добавленная RichFaces 3 в JSF 1.2, так и включенная в JSF 2.0), направлена ​​на снижение пропускной способности сети с точки зрения потребления ресурсов сервера, а не на процессор.

Из моего анализа проблема вызвана внедрением фейслетов. На основе отладчика следующие строки FaceletViewHandler класс, вызывает перестроение дерева при каждом (даже AJAX) запросе (buildBeforeRestore ложно, так buildView метод вызывается):

        // build view - but not if we're in "buildBeforeRestore"
        // land and we've already got a populated view. Note
        // that this optimizations breaks if there's a "c:if" in
        // the page that toggles as a result of request processing -
        // should that be handled? Or
        // is this optimization simply so minor that it should just
        // be trimmed altogether?
        if (!this.buildBeforeRestore
                || viewToRender.getChildren().isEmpty()) {
            this.buildView(context, viewToRender);
        }

Поэтому, на мой взгляд, решить проблему перестройки дерева при каждом запросе - это углубиться в реализацию Facelets и выполнить повторную реализацию... Я бы предпочел реструктурировать представление и минимизировать количество компонентов, поэтому время сборки дерева невелико.

Другие вопросы по тегам