Улучшение производительности JSF

Я работаю над WebApp с использованием JSF 2.2 + Primefaces... проект быстро развивается, и первый тест производительности был очень плохим (из-за моих слабых знаний о JSF LifeCylce в сочетании с нефункциональными требованиями - то есть с полностью ajax-сайтом), затем мы могли бы немного улучшить, но результаты все же не такие, как ожидалось. (У нас есть время от 300 до 1500 мс в зависимости от действия, идея в том, чтобы иметь производительность около 500 мс, отдача или взятие). В основном фаза восстановления и отклика рендеринга являются потребителями времени (в других случаях затраченное время бесполезно). Для некоторых действий Invoke Aplication также требуется время (из-за вызовов БД).

После прочтения большого количества статей в Интернете было принято во внимание множество замечательных советов (многие, конечно, из stackru), таких как:

  • Улучшение запросов к БД

у нас есть несколько сложных, которые выполняются с двумя запросами Hibernate Criterias, поэтому у нас есть работа здесь. (может быть, использовать чисто SQL-запросы, а на сложные использовать подзапросы?)

  • Никогда не определяю бизнес-логику для получателей Бина

Понял!

  • Установка соответствующих областей действия для хранения бобов и хранение на них ничего, кроме необходимых вещей

У нас есть полный ajax-сайт, поэтому View Scoped для нас почти как Session Scoped, мы используем SessionBeans как своего рода "кэш" для хранения ключевых данных, которые мы не хотим получать из БД каждый раз + определяем бизнес-логику Вот.

  • Выбор правильного метода сохранения состояния JSF - Client Vs Server

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

Пока очень ясно, теперь есть несколько дополнительных советов, в которых у меня есть некоторые сомнения.

  • Используйте как можно больше ванильного HTML, и желательно использовать h: тэги, а не p: тэги

Простой HTML понятен и имеет смысл, теперь между h: и p: сколько это стоит? Например.

<p:commandButton value="Value" 
             styleClass="class" 
             actionListener="#{myBean.doStuff()}"
             ajax="true" process="@form" update="@form" 
             onsuccess="jsFunction()" />

против

<h:commandButton value="Value" 
             styleClass="class" 
             actionListener="#{myBean.doStuff()}" >
       <f:ajax execute="@form" render="@form" event="onclick" />
</h:commandButton>

или же

<ui:fragment... vs <p:fragment...

или же

<p:outputLabel value="#{myBean.value}" rendered="#{myBean.shouldRender}" />

против

<ui:fragment rendered="#{myBean.shouldRender}">
    <label>#{myBean.value}</label>
</ui:fragment>

Я уже некоторое время использую смесь Primefaces с тегами Jsf и некоторым простым HTML здесь и там (в основном PF из-за особенностей их компонентов). Теперь я понимаю, что простой HTML всегда будет быстрее, но между JSF и другим Framework? Если я пойду на это, его изменение займет много времени, и мне не хотелось бы, чтобы результат знал, что это вообще не имеет значения.

  • Пользовательские теги Facelets против составных компонентов

Я думаю, что здесь ключ. Все еще есть некоторые сомнения по поводу их различий, в реализации обоих, CC довольно просты и гибки в использовании, но имеют недостаток в том, что они полностью включены в ViewTree и JSF повторно генерирует для каждого запроса (если я не ошибаюсь) в то время как пользовательские теги кажутся немного более сложными в использовании (не так много), но имеют то преимущество, что в ViewTree включено только то, что фактически отображается, и ничего более, что делает RESTORE VIEW менее трудоемким. У нас есть несколько составных компонентов и нет тегов Facelets, поэтому здесь будет много работы. Я до сих пор не нашел хорошую статью, объясняющую различия между ними, когда один должен использоваться, а когда другой (прочитал это для входных данных, сообщения используют TAGS и для более сложных вещей CC). Если идея состоит в том, чтобы предпочесть теги против CC, то в каком случае у меня не было бы выбора, вместо использования CC? Можно ли использовать пользовательские теги внутри CC, чтобы облегчить их обработку JSF?

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

6 ответов

Есть несколько вещей, которые вы можете сделать, чтобы улучшить производительность ваших экранов

  1. Фильтр GZIP значительно сократит время начальной загрузки. Он сжимает содержимое страницы при передаче клиентскому браузеру. См. /questions/23553990/kakov-nailuchshij-sposob-gzip-stranits-veb-prilozheniya-jsf-seam/23554008#23554008
  2. Вы можете дополнительно реализовать cacheFilter для приведения производительности ваших экранов в соответствие с пользовательским интерфейсом на основе JavaScript. Это позволит кэшировать статическое содержимое вашего экрана, например значки, изображения, таблицы стилей, сценарии JavaScript и т. Д. Вы можете контролировать, что кэшировать, а что исключать. См. /questions/5768340/filtr-staticheskih-resursov-jsf-cache/5768370#5768370
  3. Для компонентов пользовательского интерфейса на стороне клиента вы можете использовать Primefaces, который является пользовательским интерфейсом на основе JQuery.

Как проверить, использует ли мой экран gzip и кеш

Чтобы увидеть, что ваш контент уже использует gzip и кеш, в браузере Google Chrome -> щелкните правой кнопкой мыши на экране -> осмотрите -> щелкните вкладку сети -> обновите экран. Нажмите на изображения, значки, таблицы стилей и посмотрите, видите ли вы следующее в заголовке ответа

Cache-Control:max-age=2592000 если статус элемента 304 (поступающий из кеша)

Content-Encoding:gzip если статус элемента 200

Я столкнулся с той же проблемой полгода назад. Большую часть времени проводят в фазах RestoreView и RenderResponse. Если ваша проблема такая же, то вы ничего не можете сделать:

  1. использование partialSubmit="true" как можно больше
  2. Уменьшить количество компонентов
  3. Не используйте составные компоненты много

В моем конкретном случае у меня было много динамического HTML без элементов управления вводом, и я использовал составной компонент в качестве шаблона для условного рендеринга. Для увеличения производительности я использовал http://freemarker.org/ для создания динамического HTML.

PS. Мое мнение не в том, чтобы использовать JSF, если у вас есть сложные страницы со многими компонентами. Я думаю, что Гобелен более оптимизирован для этого. Он не воссоздает компоненты при каждом запросе, как это делает JSF.

RenderResponse занимает 98% вашего времени, потому что... в основном это делает JSF. Я был бы обеспокоен, если бы JSF посвятил 50% времени обработки запроса, чтобы сделать что-то кроме обработки ответа! Тебе нужно копать глубже. Рассмотрим этот пример.

Скажем, у вас есть страница, которая отображает таблицу. Вы используете компонент p: dataTable PrimeFaces, например так:

<h:html>
   <h:body>
       <p:dataTable value="#{myBean.data}">
       </p:dataTable>
   </h:body>
</h:html>

И у вас есть это @ManagedBean:

@ManagedBean(name="myBean")
public class MyBean {

    public List<MyObject> getData() { 
        return // fetch list from database;
    }
}

Каждый раз getData() называется, есть доступ к базе данных, и это время добавляет к глобальному времени фазы рендеринга. Кроме того, рендеринг p: dataTable может потребовать много вызовов getData.

Опять же, вам нужно углубиться в свое приложение и определить, где именно, на этапе рендеринга, тратится время. По моему опыту, наивные реализации @ManagedBeans имеют много кода для запросов к базе данных в тех же геттерах, на которые есть ссылки в xhtmlс, как в моем предыдущем примере. JSF (или такой компонент, как PrimeFaces p:dataTable) может вызывать эти методы получения много раз при отображении одного HTML-файла. Обычной стратегией является выборка данных только один раз с использованием события preRenderView, например:

В вашем xhtml:

<h:html>
   <f:metadata>
       <f:event type="preRenderView" listener="#{myBean.fetchDAta}"/>
   </f:metadata>
   <h:body>
       <p:dataTable value="#{myBean.data}">
       </p:dataTable>
   </h:body>
</h:html>

В вашем управляемом бобе:

@ManagedBean(name="myBean")
public class MyBean {
    private List<MyObject> data;

    public void fetchData() {
         data = // fetch data from database.
    }

    public List<MyObject> getData() { 
        return data; 
    }
 }

Я не уверен, есть ли большая разница между "p" и "h", так как оба они отображаются как html к концу. Я вижу, вы часто используете атрибут процесса. Вы можете указать конкретные идентификаторы в этом атрибуте, чтобы повысить производительность, отправляя только части формы. Еще одна идея для увеличения производительности - использовать кеш простых чисел. http://www.primefaces.org/showcase/ui/misc/cache.xhtml для нединамического контента, который вы хотите отображать очень часто (см. документацию). Я предполагаю, что "кеш" будет пытаться получить представление дерева из кеша, а не восстанавливать его.

Если вы хотите создать jsf-приложение с другим фреймворком, ваше приложение будет плохим из-за производительности для пользователей. Потому что приложение Jsf стало 6-й фазой, которая слишком долго ждет фазы рендеринга. Таким образом, вы можете использовать микро сервисы для бэкэнда и использовать javascript для фронтэнда. В результате вы можете сделать такое хорошее приложение, как производительность и архитектура. вы можете посмотреть весенние загрузочные микро сервисы для приложений Java ee

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

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

Решение проблемы состоит в том, чтобы вообще пропустить выборку данных. Он не нужен, он даже не используется, и это даже не правильные данные (не волнуйтесь, я объясню это позже). В объекте FacesContext есть метод getRenderResponse(), который возвращает true, если был вызван метод ответа рендеринга, и мы находимся в фазе рендеринга. Пока мы не отрисовываем страницу, нам на самом деле не нужны наши данные, поэтому мы загружаем их, только если этот метод возвращает true.

Например:

//generates the list of data, think of this as an expensive DB operation
private List<Integer> generateData()  {
if (!FacesContext.getCurrentInstance().getRenderResponse()) {
    return null;
}
System.out.println("Generating Data starting from "+pageNumber);
...
...
...
}

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

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

Удвойте скорость (некоторые из) ваших страниц JSF (и избегайте ошибок тоже)

Я надеюсь, что это полезно для других.

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