Serwlety c.d.

Download Report

Transcript Serwlety c.d.

Serializacja
Serializacja pozwala zamienić obiekt na
sekwencję bajtów, w sposób umożliwiający
później wierne odtworzenie jego zawartości
• Inna nazwa to trwałość (ang. persistence) – cecha
oznaczająca, że życie obiektu nie jest ograniczone
tylko do czasu działania programu
• Działa to również w sieci, pomiędzy maszynami
działającymi pod różnymi systemami operacyjnymi
• Dużo klas z bibliotek Javy jest zmodyfikowanych tak,
że wspierają serializację (np. kolekcje)
Zastosowania serializacji
• Trwałość – zapisanie obiektów na dysk oraz
odtworzenie przy kolejnym uruchomieniu programu.
• Zdalne wywoływanie metod między komputerami
poprzez RMI (ang. Remote Method Invocation).
Pozwala to obiektowi istniejącemu na jednym
komputerze zachowywać się tak, jakby istniał na
drugim komputerze. Serializacja jest używana do
przekazywania argumentów przy wywołaniu metod
odległego obiektu oraz do zwracania wartości.
• Komponenty JavaBeans – elementy z których
buduje się interfejs użytkownika. W trakcie
projektowania stan komponentu jest serializowany,
a przy starcie programu jest on odtwarzany.
Sposoby realizacji
Serializację typowo realizuje się przez:
1. Implementację w klasie, która ma być serializowana
interfejsu Serializable (nie ma żadnych metod)
Można także kontrolować przebieg serializacji przez:
2. Implementację w klasie interfejsu Externalizable
oraz jego dwóch metod: writeExternal() – zapis
obiektu i readExternal() – odczyt obiektu, musi
być też dostępny publiczny konstruktor domyślny
3. Implementację w klasie interfejsu Serializable oraz
dodatkowo (!) dwóch prywatnych metod
writeObject() i readObject()
Działanie
• Żeby zserializować obiekt, trzeba utworzyć strumień
ObjectOutputStream i wywołać jego metodę
writeObject() podając obiekt do serializacji.
Może się tu pojawić wyjątek IOException.
• Żeby odtworzyć obiekt, trzeba utworzyć strumień
ObjectInputStream, wywołać jego metodę
readObject() i dokonać rzutowania (readObject()
zwraca bowiem obiekt klasy Object).
Mogą się tu pojawić wyjątki IOException oraz
ClassNotFoundException.
• Słowo kluczowe transient pozwala wskazać, które
składowe obiektu mają nie być serializowane.
Przykład serializowania obiektów
import java.io.*;
class Wezel implements Serializable {
String nazwa;
/* ... */
}
public class Serializacja {
Wezel korzen = new Wezel();
/* ... */
void zapiszWezly() throws IOException {
/* ... utworzenie strumienia wyjściowego ... */
ObjectOutputStream out =
new ObjectOutputStream( /*strumień wyj.*/ );
out.writeObject(korzen);
}
Przykład odtwarzania obiektów
/* ... */
void przywrocWezly() throws
IOException, ClassNotFoundException {
/* ... utworzenie strumienia wejściowego ... */
ObjectInputStream in =
new ObjectInputStream( /*strumień wej.*/ );
}
}
// odczytanie obiektu i rzutowanie do
// odpowiedniego typu
korzen = (Wezel) in.readObject();
Serwlety i zasoby
• Serwlet działający w środowisku serwera J2EE
występuje tylko w jednej kopii
• Jeśli do swojego działania potrzebuje jakichś
zasobów, to może tego dokonać przy starcie,
w swojej metodzie init()
• Po skończeniu pracy (przy wyładowywaniu
serwletu z pamięci) powinien zwolnić zasoby
w swojej metodzie destroy()
• Należy przy tym uważać, żeby nie zwolnić zasobów,
które są jeszcze używane
Inicjalizacja zasobów – init()
• Jeśli inicjalizacja zasobów potrzebnych do działania
nie udała się, serwlet powinien wyrzucić wyjątek
UnavailableException
public class DBServlet extends HttpServlet {
/* ... */
public void init() throws ServletException {
establishConnection();
if (connection == null)
throw new UnavailableException(
"Couldn't get database.");
}
}
Zwalnianie zasobów – destroy()
• Zasoby można dodatkowo ustawić na null, aby
szybciej uległy procesowi odśmiecania pamięci
public class DBServlet extends HttpServlet {
/* ... */
public void destroy() {
connection.close();
connection = null;
}
/* ... */
}
Serwlety i wątki
• Serwer obsługujący serwlety umożliwia równoczesne
wykonanie kodu serwletu dla wielu żądań klientów,
tworząc wątek dla każdego żądania
• Można zagwarantować, że serwlet będzie obsługiwał
tylko jedno żądanie naraz implementując pusty
interfejs SingleThreadModel (serwer J2EE może
wtedy synchronizować dostęp do serwletu lub
tworzyć wiele komponentów Web'owych i kierować
żądania do aktualnie wolnego egzemplarza)
• Zawsze jednak trzeba zabezpieczyć się przed
niepoprawnym użyciem zasobów dzielonych
stosując metody synchronizacji wątków
Współdzielenie informacji
• Każda aplikacja webowa (web application) posiada
kontekst wykonania na serwerze J2EE, jest on
reprezentowany przez obiekt klasy ServletContext
• Konteksty są tworzone przez serwer J2EE podczas
jego startu, ew. przy przeładowaniu aplikacji, na
podstawie globalnego dla aplikacji pliku web.xml
• Istnieje jeden kontekst dla każdej aplikacji na każdej
maszynie wirtualnej, na której jest ona uruchomiona
• Klasa Servlet umożliwia dostęp do swojego
kontekstu poprzez metodę getServletContext()
Współdzielenie informacji
• Architektura serwletów umożliwia posiadanie
informacji globalnej dla całej aplikacji webowej.
W tym celu trzeba użyć metod setAttribute() oraz
getAttribute() klasy ServletContext
void setAttribute(String name, Object object)
Object getAttribute(String name) (!) potrzebne rzutowanie
void removeAttribute(String name)
• W przypadku aplikacji rozproszonej, działającej na
kilku komputerach (maszynach wirtualnych),
kontekstów jest wiele, więc nie można użyć ich do
przechowywania dzielonej informacji – trzeba użyć
innego mechanizmu, np. bazy danych
Zdarzenia cyklu życia serwletu
• Architektura serwletów przewiduje także możliwość
monitorowania i reagowania na zdarzenia związane
z cyklem życia serwletu (zdarzenia dotyczące
aplikacji lub sesji), poprzez zdefiniowanie obiektów
nasłuchujących (listeners)
• W tym celu wystarczy utworzyć klasę implementującą
odpowiedni interfejs (ServletContextListener,
ServletContextAttributeListener, HttpSessionListener
lub HttpSessionAttributeListener) oraz powiązać ją z
odpowiednią sekcją w pliku web.xml
Interfejsy zdarzeń serwletu
Zasięg
Kontekst
aplikacji
Sesja
Zdarzenie
Inicjalizacja,
destrukcja
Interfejs nasłuchujący oraz
klasa zdarzenia
ServletContextListener
ServletContextEvent
Dodano, zmieniono ServletContextAttributeListener
lub usunięto atrybut ServletContextAttributeEvent
Utworzenie,
unieważnienie,
przeterminowanie
HttpSessionListener
HttpSessionEvent
Dodano, zmieniono HttpSessionAttributeListener
lub usunięto atrybut HttpSessionBindingEvent
Sesje w serwletach HTTP
• Sesje są reprezentowane przez obiekty HttpSession
• Dostęp do sesji odbywa się przez wywołanie metody
obiektu żądania: request.getSession() – zwraca
ona obiekt sesji związany z żądaniem lub tworzy
nową sesję, jeśli żądanie nie ma jeszcze obiektu sesji
• Użycie sesji może spowodować wysłanie nagłówka
HTTP, więc obiekt sesji musi być odczytany przed
uzyskaniem obiektu strumienia PrintWriter
• Obiekt sesji służy głównie do przechowywania par
atrybut-wartość, wykorzystuje się tu metody
setAttribute() oraz getAttribute()
Zarządzanie sesjami
• Stworzenie sesji, jej modyfikacje, unieważnienie, czy
przeterminowanie (timeout) generują zdarzenia, na
które może reagować obiekt nasłuchujący
(np. wykonując odczyt lub zapis do bazy danych)
• Mechanizm sesji przechowuje wszystkich informacje
związane z sesją na serwerze, zaś do użytkownika
wysyłany jest jedynie identyfikator sesji w postaci
ciasteczka (cookie)
• Aby radzić sobie z sytuacją, gdy użytkownik wyłączy
ciasteczka lub ich nie obsługuje, należy używać
metody response.encodeURL() – która w takim
przypadku dopisuje identyfikator sesji do adresu
Dostęp współbieżny do zasobów
dzielonych
• Dobrym sposobem na dzielenie informacji pomiędzy
wieloma serwletami jednej aplikacji jest utworzenie
dodatkowej klasy (klasy zasobów), która będzie
przechowywać dane i udostępniać metody do ich
odczytu i modyfikacji – obiekt tej klasy można
udostępnić w kontekście aplikacji (ServletContext)
• Powstaje jednak problem, gdy wiele serwletów (lub
wątków) chce równocześnie modyfikować dane
• Jednym z rozwiązań jest opatrzenie metod klasy
zasobów modyfikatorem synchronized