Jest to spowodowane charakterem odroczonych wyrażeń #{}
(zwróć uwagę, że standardowe wyrażenia „starsze” ${}
zachowują się dokładnie tak samo, gdy zamiast JSP użyto Faceletów). Odroczone wyrażenie nie jest natychmiast analizowane, ale jest tworzone jako ValueExpression
obiekt, a metoda pobierająca wyrażenie jest wykonywana za każdym razem, gdy wywoływany jest kod ValueExpression#getValue()
.
Zwykle będzie to wywoływane jeden lub dwa razy na cykl JSF żądanie-odpowiedź, w zależności od tego, czy składnik jest składnikiem wejściowym czy wyjściowym ( dowiedz się tutaj ). Jednak ta liczba może wzrosnąć (znacznie), gdy jest używana w iteracji komponentów JSF (takich jak <h:dataTable>
i <ui:repeat>
), lub tu i tam w wyrażeniu boolowskim, takim jak rendered
atrybut. JSF (konkretnie EL) w ogóle nie buforuje obliczonego wyniku wyrażenia EL, ponieważ może zwracać różne wartości przy każdym wywołaniu (na przykład, gdy jest zależny od aktualnie iterowanego wiersza danych).
Ocena wyrażenia EL i wywołanie metody gettera to bardzo tania operacja, więc ogólnie nie powinieneś się tym przejmować. Jednak historia zmienia się, gdy z jakiegoś powodu wykonujesz kosztowną logikę DB / biznesową w metodzie gettera. Zostanie to ponownie wykonane za każdym razem!
Getter w JSF podporowych fasoli powinny być zaprojektowane w taki sposób, że tylko powrót już przygotowaną własność i nic więcej, dokładnie jak na specyfikacji JavaBeans . Nie powinny w ogóle robić drogiej logiki DB / biznesowej. W tym celu @PostConstruct
należy zastosować metody detektora komponentu bean i / lub (action). Są one wykonywane tylko raz w pewnym momencie cyklu życia JSF opartego na żądaniach i właśnie tego chcesz.
Oto podsumowanie wszystkich różnych właściwych sposobów wstępnego ustawiania / ładowania właściwości.
public class Bean {
private SomeObject someProperty;
@PostConstruct
public void init() {
// In @PostConstruct (will be invoked immediately after construction and dependency/property injection).
someProperty = loadSomeProperty();
}
public void onload() {
// Or in GET action method (e.g. <f:viewAction action>).
someProperty = loadSomeProperty();
}
public void preRender(ComponentSystemEvent event) {
// Or in some SystemEvent method (e.g. <f:event type="preRenderView">).
someProperty = loadSomeProperty();
}
public void change(ValueChangeEvent event) {
// Or in some FacesEvent method (e.g. <h:inputXxx valueChangeListener>).
someProperty = loadSomeProperty();
}
public void ajaxListener(AjaxBehaviorEvent event) {
// Or in some BehaviorEvent method (e.g. <f:ajax listener>).
someProperty = loadSomeProperty();
}
public void actionListener(ActionEvent event) {
// Or in some ActionEvent method (e.g. <h:commandXxx actionListener>).
someProperty = loadSomeProperty();
}
public String submit() {
// Or in POST action method (e.g. <h:commandXxx action>).
someProperty = loadSomeProperty();
return "outcome";
}
public SomeObject getSomeProperty() {
// Just keep getter untouched. It isn't intented to do business logic!
return someProperty;
}
}
Należy pamiętać, że należy nie używać konstruktora lub bloku inicjalizacji fasoli do pracy, ponieważ może to być wywoływane wielokrotnie jeśli używasz ramy zarządzania fasola, który używa proxy, takie jak CDI.
Jeśli naprawdę nie ma dla ciebie innych sposobów, z powodu pewnych restrykcyjnych wymagań projektowych, powinieneś wprowadzić leniwe ładowanie w metodzie gettera. To znaczy null
, jeśli właściwość jest , a następnie załaduj i przypisz ją do właściwości, w przeciwnym razie zwróć ją.
public SomeObject getSomeProperty() {
// If there are really no other ways, introduce lazy loading.
if (someProperty == null) {
someProperty = loadSomeProperty();
}
return someProperty;
}
W ten sposób kosztowna logika DB / biznes nie będzie niepotrzebnie wykonywana przy każdym wywołaniu gettera.
Zobacz też:
FacesContext#getCurrentPhaseId()
.Dzięki JSF 2.0 możesz dołączyć detektor do zdarzenia systemowego
Alternatywnie możesz umieścić stronę JSF w
f:view
taguźródło
Napisałem artykuł o tym, jak buforować moduł pobierający ziarna JSF za pomocą Spring AOP.
Tworzę prosty,
MethodInterceptor
który przechwytuje wszystkie metody opatrzone adnotacją specjalną adnotacją:Ten przechwytywacz jest używany w wiosennym pliku konfiguracyjnym:
Mam nadzieję, że to pomoże!
źródło
Pierwotnie opublikowane na forum PrimeFaces @ http://forum.primefaces.org/viewtopic.php?f=3&t=29546
Ostatnio miałem obsesję na punkcie oceny wydajności mojej aplikacji, dostrajania zapytań JPA, zastępowania dynamicznych zapytań SQL zapytaniami nazwanymi, i właśnie dziś rano zrozumiałem, że metoda gettera była bardziej GORĄCĄ SPOTĄ w Java Visual VM niż reszta mój kod (lub większość mojego kodu).
Metoda Gettera:
Odwołany przez ui: include in w index.xhtml
Poniżej zobaczysz, że PageNavigationController.getGmapsAutoComplete () to HOT SPOT (problem z wydajnością) w Java Visual VM. Jeśli spojrzysz w dół, na zrzucie ekranu zobaczysz, że getLazyModel (), leniwa metoda pobierania danych PrimeFaces, jest również gorącym punktem, tylko wtedy, gdy użytkownik wykonuje wiele „leniwych danych” typu rzeczy / operacji / zadań w aplikacji. :)
Zobacz (oryginalny) kod poniżej.
Przywoływane przez następujące w index.xhtml:
Rozwiązanie: ponieważ jest to metoda „pobierająca”, przenieś kod i przypisz wartość do gmapsAutoComplete przed wywołaniem metody; patrz kod poniżej.
Wyniki testu: PageNavigationController.getGmapsAutoComplete () nie jest już GORĄCYM SPOTEM w Java Visual VM (już się nawet nie pokazuje)
Udostępniam ten temat, ponieważ wielu ekspertów ekspertów radziło młodszym programistom JSF, aby NIE dodawali kodu w metodach „getter”. :)
źródło
Jeśli używasz CDI, możesz użyć metod producentów. Będzie wywoływany wiele razy, ale wynik pierwszego wywołania jest buforowany w zakresie komponentu bean i jest skuteczny dla osób pobierających, które obliczają lub inicjalizują ciężkie obiekty! Zobacz tutaj , aby uzyskać więcej informacji.
źródło
Prawdopodobnie możesz użyć AOP do stworzenia jakiegoś aspektu, który buforuje wyniki naszych programów pobierających przez konfigurowalny okres czasu. Zapobiegnie to konieczności kopiowania i wklejania kodu szablonu na dziesiątkach akcesoriów.
źródło
Nazywamy to przedwczesną optymalizacją. W rzadkim przypadku, gdy profilujący mówi ci, że obliczenie właściwości jest tak wyjątkowo kosztowne, że trzykrotne jej wywołanie zamiast jednego ma znaczący wpływ na wydajność, dodajesz buforowanie, tak jak to opisano. Ale jeśli nie zrobisz czegoś naprawdę głupiego, takiego jak faktoryzacja liczb pierwszych lub uzyskiwanie dostępu do bazy danych w module pobierającym, Twój kod najprawdopodobniej ma kilkanaście gorszych nieefektywności w miejscach, o których nigdy nie pomyślałeś.
źródło
Radziłbym również przy użyciu takich ram jak Primefaces zamiast zapasów JSF, rozwiązują one takie problemy przed zespołem e JSF. gw podstawach można ustawić częściowe przesłanie. W przeciwnym razie BalusC dobrze to wyjaśnił.
źródło
To wciąż duży problem w JSF. Na przykład, jeśli masz metodę
isPermittedToBlaBla
kontroli bezpieczeństwa i według niej masz,rendered="#{bean.isPermittedToBlaBla}
metoda ta będzie wywoływana wiele razy.Kontrola bezpieczeństwa może być skomplikowana np. Zapytanie LDAP itp. Musisz tego uniknąć za pomocą
i musisz upewnić się, że w ramach sesji fasola to na żądanie.
Ich zdaniem JSF musi zaimplementować tutaj niektóre rozszerzenia, aby uniknąć wielu połączeń (np. Adnotacja wywołuje
@Phase(RENDER_RESPONSE)
tę metodę tylko raz poRENDER_RESPONSE
fazie ...)źródło