Logika biznesowa, skomplikowane operacje, dostęp do bazy, itp.
Należy pamiętać, że JSF to technologia za pomocą której tworzymy wygląd naszej aplikacji, czyli nie powinniśmy zaszywać w niej skomplikowanych obliczeń, dostępu do bazy danych, itd. Managed Beand jest częścią JSF i obowiązują go takie same reguły. 99% MB powinno być tylko pośrednikiem między tym co jest na stronach xhtml, a tym co jest w kodzie Java. Pytanie co z tym 1%?, zawsze znajdą się jakieś wyjątki :), ale jeśli twoja aplikacja składa się z samych wyjątków, to znaczy że coś jest nie tak.
Racjonalne wykorzystanie zmiennych
JSF i technologie pośrednie, mają kilka zasięgów do naszej dyspozycji:
- @RequestScoped czyli standardowy request aplikacji. Wszystko co żyje w tym zasięgu jest dostępne tylko podczas jednego requestu.
- @ViewScoped zasięg idealny dla AJAX'owych komponentów. Wszystkie komponenty w tym zasięgu są aktywne, do momentu kiedy nie przejdziemy na inną stronę. Zasięg nie jest dostępny dla JSF 1.2
- @SessionScoped czyli zasięg sesyjny, idealny do trzymania wszelkich informacji do których często się odwołujemy (np. o zalogowanym użytkowniku)
- @ApplicationScoped czyli zasięg aplikacyjny. Wszystko co w nim żyje jest dostępne przez cały okres życia naszej aplikacji.
Gettery ...
Jedna z ważniejszych zasad jaka dotyczy JSF, to nie umieszczanie w metodach get, referencji do innych metod/obiektów realizujących jakąkolwiek logikę, ponieważ metody get wywoływane są przez silnik JSF kilkakrotnie podczas jednego requesta. Jeśli zapomnimy o tej zasadzie to nagle nasze skomplikowane metody przetwarzające dane (czyli najczęściej jest to jakiś select do bazy danych i/lub obróbka danych w javie) wywoływane są kilkakrotnie. Efektem takiego postępowania jest znaczne wydłużenie się ładowania strony. Strona, która powinna wczytać się w 3-4s, nagle wczytuje się w ponad 10 sekund, itd.
Oto krótki przykład- jak taki kod wygląda.
package pl.blogspot.mkorwel.myapp.view.faces; import java.io.Serializable; import java.util.List; import javax.faces.bean.ManagedBean; import javax.faces.bean.RequestScoped; import pl.blogspot.mkorwel.myapp.model.Person; import pl.blogspot.mkorwel.myapp.service.PersonService; @ManagedBean @RequestScoped public class PersonBrowser implements Serializable { //jakieś wstrzyknięcie private PersonService personService; public List<Person> getPersons() { return this.personService.getPersons(); } }
Jeśli ten kod przypomina wam wasze MB to znaczy, że trzeba zakasać rękawy i trochę popracować. Pierwszym pomysł na jaki wpadamy to przypisanie naszej listy osób do zmiennej i wywoływanie servicu tylko kiedy jest ona null'em. Po wprowadzeniu naszego hackerskiego tricku w życie, kod wygląda mniej więcej tak:
package pl.blogspot.mkorwel.myapp.view.faces; import java.io.Serializable; import java.util.List; import javax.faces.bean.ManagedBean; import javax.faces.bean.RequestScoped; import pl.blogspot.mkorwel.myapp.model.Person; import pl.blogspot.mkorwel.myapp.service.PersonService; @ManagedBean @RequestScoped public class PersonBrowser implements Serializable { // jakieś wstrzyknięcie private PersonService personService; private List<Person> persons; public List<Person> getPersons() { if (this.persons == null) { this.persons = this.personService.getPersons(); } return this.persons; } }Tak przerobiony kod działa już po naszej myśli, tz. metoda z klasy servicowej wywołuje się tylko raz. Nasza strona znacznie przyspieszyła i wydaje się, że zadanie wykonane. Niestety po dłuższym namyśle nasz instynkt programisty podpowiada nam, że coś jest nie tak. Do rozwiązania tego problemu musimy sięgnąć trochę głębiej, a mianowicie do adnotacji @PostConstruct. Taką adnotacją wskazujemy metodę, która będzie wywołana na początku tworzenia się Managed Beanów (coś a'la konstruktor) i to właśnie w tej metodzie, powinniśmy zainicjalizować listę naszych osób. Po wprowadzeniu poprawek całość powinna prezentować się tak jak poniżej.
package pl.blogspot.mkorwel.myapp.view.faces; import java.io.Serializable; import java.util.List; import javax.annotation.PostConstruct; import javax.faces.bean.ManagedBean; import javax.faces.bean.RequestScoped; import pl.blogspot.mkorwel.myapp.model.Person; import pl.blogspot.mkorwel.myapp.service.PersonService; @ManagedBean @RequestScoped public class PersonBrowser implements Serializable { // jakieś wstrzyknięcie private PersonService personService; private List<Person> persons; public List<Person> getPersons() { return this.persons; } @PostConstruct public void init() { this.persons = this.personService.getPersons(); } }
Jeśli macie jakieś inne ciekawe przygody związane z JSF, to zapraszam do dyskusji w komentarzach.