Dlaczego JSF zapisuje stan komponentów UI na serwerze?

108
  1. Do jakiego momentu JSF zapisuje stan komponentów UI po stronie serwera i kiedy dokładnie informacje o stanie komponentu UI są usuwane z pamięci serwera? Kiedy zalogowany użytkownik aplikacji nawiguje po stronach, czy stan komponentów będzie się gromadził na serwerze?

  2. Nie rozumiem, jakie są korzyści z utrzymywania stanu komponentów interfejsu użytkownika na serwerze!? Czy bezpośrednie przekazywanie zweryfikowanych / przekonwertowanych danych do zarządzanych komponentów bean nie jest wystarczające? Czy mogę lub powinienem spróbować tego uniknąć?

  3. Czy to nie zajmuje zbyt dużo pamięci po stronie serwera, jeśli istnieją tysiące jednoczesnych sesji użytkowników? Mam aplikację, w której użytkownicy mogą publikować blogi na określone tematy. Te blogi są dość duże. Kiedy pojawi się wiadomość zwrotna lub prośba o przeglądanie blogów, czy dane dużej strony zostaną zapisane jako część stanu komponentów? To pochłonęłoby zbyt dużo pamięci. Czy to nie problem?


Aktualizacja 1:

Teraz nie jest już konieczne zapisywanie stanu podczas korzystania z JSF. Dostępna jest wysokowydajna implementacja bezstanowego JSF. Zobacz ten blog i to pytanie, aby uzyskać szczegółowe informacje i dyskusję. Istnieje również otwarty problem, który należy uwzględnić w specyfikacjach JSF, opcję zapewnienia trybu bezstanowego dla JSF. (PS Rozważ możliwość głosowania w sprawach tego i tego, jeśli jest to dla Ciebie przydatna funkcja).


Aktualizacja 2 (24-02-2013):

Świetna wiadomość, że Mojarra 2.1.19 wychodzi z trybem bezstanowym !

Spójrz tutaj:

http://weblogs.java.net/blog/mriem/archive/2013/02/08/jsf-going-stateless?force=255

http://java.net/jira/browse/JAVASERVERFACES-2731

http://balusc.blogspot.de/2013/02/stateless-jsf.html

Rajat Gupta
źródło

Odpowiedzi:

199

Dlaczego JSF musi zapisywać stan komponentów UI po stronie serwera?

Ponieważ protokół HTTP jest bezstanowy, a JSF jest stanowy. Drzewo komponentów JSF podlega dynamicznym (programowym) zmianom. JSF musi po prostu znać dokładny stan, w jakim był, kiedy formularz został wyświetlony użytkownikowi końcowemu, aby mógł z powodzeniem przetworzyć cały cykl życia JSF w oparciu o informacje dostarczone przez oryginalne drzewo komponentów JSF, gdy formularz został przesłany z powrotem do serwer. Drzewo komponentów zawiera informacje o nazwach parametrów żądania, niezbędnych konwerterach / walidatorach, powiązanych właściwościach zarządzanego komponentu bean i metodach akcji.


Do jakiego momentu JSF zapisuje stan komponentów UI po stronie serwera i kiedy dokładnie informacje o stanie komponentu UI są usuwane z pamięci serwera?

Te dwa pytania wydają się sprowadzać do tego samego. W każdym razie jest to specyficzne dla implementacji, a także zależne od tego, czy stan jest zapisany na serwerze czy kliencie. Nieco przyzwoita implementacja usunie ją, gdy wygasła lub gdy kolejka jest pełna. Na przykład Mojarra ma domyślny limit 15 widoków logicznych, gdy zapisywanie stanu jest ustawione na sesję. Można to skonfigurować za pomocą następującego parametru kontekstu w web.xml:

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

Zobacz także Mojarra FAQ dla innych parametrów specyficznych dla Mojarra i tę powiązaną odpowiedź com.sun.faces.numberOfViewsInSession vs com.sun.faces.numberOfLogicalViews


Kiedy zalogowany użytkownik aplikacji nawiguje po stronach, czy stan komponentów będzie się gromadził na serwerze?

Technicznie zależy to od implementacji. Jeśli mówisz o nawigacji między stronami (tylko żądania GET), Mojarra nie zapisuje niczego w sesji. Jeśli są to jednak żądania POST (formularze z linkami poleceń / przyciskami), Mojarra zapisze stan każdego formularza w sesji do maksymalnego limitu. Umożliwia to użytkownikowi końcowemu otwieranie wielu formularzy na różnych kartach przeglądarki w tej samej sesji.

Lub, gdy zapisywanie stanu jest ustawione na klienta, JSF nie przechowuje niczego w sesji. Możesz to zrobić za pomocą następującego parametru kontekstu w web.xml:

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

Następnie zostanie on serializowany do zaszyfrowanego ciągu w ukrytym polu wejściowym z nazwą javax.faces.ViewStateformularza.


Nie rozumiem, jakie są korzyści z utrzymywania stanu składnika interfejsu użytkownika po stronie serwera. Czy bezpośrednie przekazywanie zweryfikowanych / przekonwertowanych danych do zarządzanych komponentów bean nie jest wystarczające? Czy mogę / powinienem spróbować tego uniknąć?

To nie wystarczy, aby zapewnić integralność i solidność JSF. JSF to dynamiczna struktura z jednym punktem kontroli. Bez zarządzania państwem, jeden byłby w stanie naciąganie / Hack żądania HTTP w określony sposób (np manipulacyjny disabled, readonlya renderedatrybuty), aby robić różne JSF-i potencjalnie hazardful- rzeczy. Byłby nawet podatny na ataki CSRF i phishing.


I czy nie zajmie to zbyt dużo pamięci po stronie serwera, jeśli są tysiące jednoczesnych sesji użytkowników? Mam aplikację, w której użytkownicy mogą publikować blogi na określone tematy. Te blogi są dość duże. Kiedy pojawi się wiadomość zwrotna lub prośba o przeglądanie blogów, duże blogi zostaną zapisane jako część stanu komponentów. Zajmowałoby to zbyt dużo pamięci. Czy to nie problem?

Pamięć jest szczególnie tania. Po prostu daj serwerowi aplikacji wystarczającą ilość pamięci. Lub jeśli przepustowość sieci jest dla Ciebie tańsza, po prostu przełącz zapisywanie stanu po stronie klienta. Aby znaleźć najlepsze dopasowanie, po prostu stresuj i sprofiluj swoją aplikację internetową z przewidywaną maksymalną liczbą jednoczesnych użytkowników, a następnie daj serwerowi aplikacji 125% ~ 150% maksymalnej zmierzonej pamięci.

Zwróć uwagę, że JSF 2.0 znacznie poprawiło zarządzanie stanem. Jest to możliwe, aby zapisać stan częściowego (np tylko<h:form> zostaną zapisane zamiast całej rzeczy z <html>całą drogę do końca). Na przykład Mojarra to robi. Przeciętny formularz z 10 polami wejściowymi (każde z etykietą i komunikatem) oraz 2 przyciskami zajmowałby nie więcej niż 1 KB. Przy 15 wyświetleniach w sesji nie powinno to być więcej niż 15 KB na sesję. Przy ~ 1000 jednoczesnych sesji użytkowników nie powinno to przekraczać 15 MB.

Twoje obawy powinny być bardziej skoncentrowane na rzeczywistych obiektach (zarządzanych komponentach bean i / lub nawet jednostkach bazy danych) w sesji lub zakresie aplikacji. Widziałem wiele kodów i projektów, które niepotrzebnie duplikują całą tabelę bazy danych do pamięci Javy w smaku fasoli o zasięgu sesji, gdzie zamiast języka SQL do filtrowania / grupowania / porządkowania rekordów używana jest Java. Przy ~ 1000 rekordów z łatwością przekroczyłoby to 10 MB na sesję użytkownika .

BalusC
źródło
1
Czy możesz wyjaśnić # 2? Dlaczego nie można po prostu odtworzyć drzewa komponentów przy każdym żądaniu? Jaki stan faktycznie należy przechowywać między żądaniami i dlaczego? Wydaje się, że jedynym powodem zapisywania drzewa komponentów między żądaniami byłaby wydajność.
Ryan,
Bardziej szczegółowe pytanie tutaj: stackoverflow.com/questions/7349174/…
Ryan
Twoja odpowiedź była dla mnie bardzo jasna! Kwestie dotyczące wydajności i skalowalności JSF mają nieodłączny związek z implementacją programisty! Trzeba wiedzieć, jak używać technologii we właściwy sposób!
Lucas Batistussi
„Po prostu daj serwerowi aplikacji wystarczającą ilość pamięci”. Erm, odnoszę wrażenie, że mówimy tutaj o sprawach na poziomie przedsiębiorstwa, jeśli mówimy o tysiącach jednoczesnych sesji użytkowników. Jeśli masz sprzęt klasy korporacyjnej w przedsiębiorstwie, nie możesz po prostu „zapewnić serwerowi aplikacji wystarczającej ilości pamięci”, tak jak możesz w swoim domowym komputerze z systemem Linux.
stu
Twoja odpowiedź była bardzo jasna i dziękuję za to. Dlaczego zakres JSF flash zniknął, jeśli ustawiono javax.faces.PARTIAL_STATE_SAVING na true. getFacesContext (). getExternalContext (). getFlash (). put ("buildingId", buildingId).
Maj Thet