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.