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

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

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

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

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

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

Получил это!

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

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

  • Выбор правильного метода сохранения состояния 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>

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

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

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

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

Ответы

Ответ 1

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

  1. Максимально используйте partialSubmit="true"
  2. используйте атрибут execute (или PrimeFaces process), чтобы уменьшить обработку на стороне сервера
  3. Уменьшите количество компонентов
  4. Не используйте многокомпонентные компоненты

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

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

Ответ 2

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

  • Фильтр GZIP значительно сократит время начальной загрузки. Он сжимает содержимое страницы при передаче в клиентский браузер. См. fooobar.com/questions/9608/...
  • Вы можете дополнительно реализовать cacheFilter, чтобы обеспечить производительность ваши экраны совпадают с пользовательским интерфейсом на основе JavaScript. Это будет кэшировать статический контент вашего экрана, такой как значки, изображения, таблицы стилей, javascripts и т.д. Вы можете контролировать, что нужно кэшировать и что исключать. См. fooobar.com/questions/8784/...
  • Для компонентов пользовательского интерфейса на стороне клиента вы можете использовать Primefaces, который является JQuery основанный на пользовательском интерфейсе.

Как проверить, работает ли на моем экране gzip и кеш

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

Cache-Control:max-age=2592000, если статус элемента равен 304 (из кеша)

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

Ответ 3

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.

Опять же, вам нужно углубиться в ваше приложение и определить, где именно на этапе визуализации тратится время. По моему опыту, наивные реализации @ManagedBean имеют много кода запроса базы данных в тех же геттерах, на которые ссылаются в xhtml s, как в моем предыдущем примере. JSF (или компонент, такой как PrimeFaces p: dataTable) может многократно использовать эти геттеры при рендеринге одного xhtml. Общей стратегией является получение данных только один раз, используя событие 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>

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

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

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

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

Ответ 4

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

Ответ 5

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

Ответ 6

Я прочитал интересную статью о скорости ускорения 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 (и ошибки ошибок)

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