Professional Documents
Culture Documents
PRZYKADOWY ROZDZIA
SPIS TRECI
KATALOG KSIEK
KATALOG ONLINE
ZAMW DRUKOWANY KATALOG
TWJ KOSZYK
DODAJ DO KOSZYKA
CENNIK I INFORMACJE
ZAMW INFORMACJE
O NOWOCIACH
ZAMW CENNIK
CZYTELNIA
FRAGMENTY KSIEK ONLINE
Spring Framework.
Profesjonalne tworzenie
oprogramowania w Javie
Autorzy: Rod Johnson, Juergen Hoeller, Alef
Arendsen, Thomas Risberg, Colin Sampaleanu
Tumaczenie: Piotr Rajca, Mikoaj Szczepaniak
ISBN: 83-246-0208-9
Tytu oryginau: Professional Java Development
with the Spring Framework
Format: B5, stron: 824
Spring to szkielet wytwarzania aplikacji (framework), dziki ktremu proces budowania
oprogramowania w jzyku Java dla platformy J2EE staje si znacznie prostszy
i efektywniejszy. Spring oferuje usugi, ktre mona z powodzeniem uywa
w wielu rodowiskach od apletw po autonomiczne aplikacje klienckie, od aplikacji
internetowych pracujcych w prostych kontenerach serwletw po zoone systemy
korporacyjne pracujce pod kontrol rozbudowanych serwerw aplikacji J2EE.
Spring pozwala na korzystanie z moliwoci programowania aspektowego, znacznie
sprawniejsz obsug relacyjnych baz danych, byskawiczne budowanie graficznych
interfejsw uytkownika oraz integracj z innymi szkieletami takimi, jak Struts czy JSF.
Ksika Spring Framework. Profesjonalne tworzenie oprogramowania w Javie odkryje
przed Tob wszystkie tajniki stosowania Springa w procesie wytwarzania systemw
informatycznych dla platformy J2EE. Dowiesz si, jak efektywnie korzysta
z najwaniejszych skadnikw szkieletu Spring i poznasz ich rol w budowaniu aplikacji.
Nauczysz si nie tylko tego, co mona zrealizowa za pomoc poszczeglnych usug,
ale take tego, w jaki sposb zrobi to najlepiej. W kolejnych wiczeniach
przeanalizujesz proces tworzenie kompletnej aplikacji w oparciu o Spring.
W ksice poruszono m.in. tematy:
Wydawnictwo Helion
ul. Chopina 6
44-100 Gliwice
tel. (32)230-98-63
e-mail: helion@helion.pl
Wstp .........................................................................................................................................................19
Rozdzia 1. Wprowadzenie do Springa .................................................................................................... 27
Dlaczego Spring? ........................................................................................................ 27
Problemy zwizane z tradycyjnym podejciem do programowania dla platformy J2EE ... 27
Lekkie frameworki .................................................................................................. 31
Podstawowe skadniki Springa ................................................................................ 32
Zalety Springa ............................................................................................................ 34
Kontekst Springa ........................................................................................................ 37
Technologie ........................................................................................................... 37
Techniki ................................................................................................................ 51
Zwizki z pozostaymi frameworkami ....................................................................... 52
Budowa architektury aplikacji opartej na frameworku Spring ........................................... 56
Szerszy kontekst ................................................................................................... 57
Trwao i integracja .............................................................................................. 58
Obiekty usug biznesowych ..................................................................................... 62
Prezentacja ........................................................................................................... 63
Przyszo .................................................................................................................. 65
Harmonogram wydawania kolejnych wersji ............................................................... 66
Ewolucja Javy i platformy J2EE ................................................................................ 66
Wspczesny kontekst technologiczny ...................................................................... 69
Standardy i otwarty dostp do kodu rdowego ....................................................... 69
Projekt Spring i spoeczno programistw .................................................................... 70
Historia ................................................................................................................. 71
Krtkie omwienie moduw Springa ....................................................................... 73
Obsugiwane rodowiska ........................................................................................ 78
Podsumowanie ........................................................................................................... 78
Spis treci
Spis treci
Spis treci
10
10
Spis treci
11
11
12
Skorowidz ..............................................................................................................................................785
12
Sercem Springa jest funkcjonalno lekkiego kontenera IoC (ang. Inversion of Control). Do
skonfigurowania i waciwego powizania obiektw aplikacji z obiektami frameworka (oraz
zarzdzania ich cyklami ycia) mona uy jednego lub wielu egzemplarzy tego kontenera.
Podstawowe cechy kontenera IoC daj nam pewno, e zdecydowana wikszo tych
obiektw nie bdzie zawieraa zalenoci wicych je z samym kontenerem, zatem relacje
pomidzy obiektami mona wyraa za pomoc tak naturalnych rozwiza (jzyka Java)
jak interfejsy czy abstrakcyjne klasy bazowe, co niemal w stu procentach uniezalenia
nas od sposobu implementacji tych obiektw oraz lokalizacji ich zalenoci. Okazuje si,
e kontener IoC jest podstaw dla bardzo wielu funkcji i mechanizmw, ktre bdziemy
analizowali w tym i kolejnych rozdziaach.
Z tego rozdziau dowiesz si, jak konfigurowa i korzysta z fabryk komponentw Springa
oraz kontekstw aplikacji, czyli dwch podstawowych skadnikw decydujcych o ksztacie
i funkcjonalnoci kontenera IoC tego frameworka. Poznasz interfejsy BeanFactory i ApplicationContext wraz ze wszystkimi wanymi interfejsami i klasami pokrewnymi, ktre s
wykorzystywane zawsze wtedy, gdy naley programowo utworzy lub uzyska dostp do
kontenera IoC. W niniejszym rozdziale skupimy si na tych odmianach interfejsw BeanFactory i ApplicationContext, ktre mona deklaratywnie konfigurowa za porednictwem
odpowiednich dokumentw XML. Wspomniane interfejsy stanowi podstawow funkcjonalno w zakresie konfigurowania i korzystania z kontenera IoC i s stosowane przez
uytkownikw Springa w zdecydowanej wikszoci przypadkw. Warto jednak pamita, e
Spring oddziela konfiguracj kontenera od mechanizmw jego uytkowania. Podczas lektury
kolejnego rozdziau przekonasz si, e dostp do wszystkich moliwoci kontenera mona
uzyskiwa zarwno za porednictwem konfiguracji programowej, jak i alternatywnych formatw deklaratywnych.
81
82
82
83
Zgodnie z dobrymi praktykami napisano te przypadek testowy, ktry weryfikuje prawidowe funkcjonowanie tego kodu. Jeli uyjemy popularnego narzdzia JUnit, kod takiego
testu moe mie nastpujc posta:
public class WeatherServiceTest extends TestCase {
public void testSample1() throws Exception {
WeatherService ws = new WeatherService();
Double high = ws.getHistoricalHigh(new GregorianCalendar(2004, 0, 1).getTime());
// w tym miejscu powiniene umieci dodatkowy kod sprawdzajcy zwracan warto
}
}
Nasza usuga pogodowa wykorzystuje dane pogodowe w formie obiektu DAO (obiektu dostpu do danych; ang. Data Access Object), ktry jest niezbdny do uzyskania danych historycznych. Do obsugi obiektu DAO program wykorzystuje co prawda interfejs WeatherDao,
jednak w przedstawionym przykadzie usuga pogodowa bezporednio tworzy egzemplarz
konkretnego, znanego typu DAO, ktry implementuje ten interfejs: StaticDataWeatherDaoImpl. Dodatkowo nasza aplikacja testowa, WeatherServiceTest, bezporednio wykorzystuje konkretn klas WeatherService (eliminuje moliwo specjalizacji). Prezentowany
przykad zakodowano bez korzystania z technik IoC. O ile usuga pogodowa wsppracuje
z odpowiednim obiektem DAO za porednictwem interfejsu, konkretny egzemplarz obiektu
83
84
Do zarzdzania egzemplarzem usugi pogodowej uyjemy kontekstu aplikacji Springa, a konkretnie klasy ClassPathXmlApplicationContext, i upewnimy si, e kontekst aplikacji otrzyma
obiekt DAO naszej usugi, z ktrym bdzie mg wsppracowa. W pierwszej kolejnoci
musimy zdefiniowa plik konfiguracyjny w formacie XML, applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?<
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd"<
<beans<
<bean id="weatherService" class="ch02.sample2.WeatherServiceImpl"<
<property name="weatherDao"<
<ref local="weatherDao"/<
84
85
</property<
</bean<
<bean id="weatherDao" class="ch02.sample2.StaticDataWeatherDaoImpl"<
</bean<
</beans<
85
86
86
87
<beans<
<bean id="weatherService" class="ch02.sample4.WeatherServiceImpl"<
87
88
Zauwa, e nakazalimy kontenerowi, aby nie traktowa obiektu DAO jak singleton, zatem
kade wywoanie metody getWeatherDao() moe zwrci nowy egzemplarz tego obiektu.
Gdybymy tego nie zrobili, metoda za kadym razem zwracaaby ten sam egzemplarz singletonu (skadowany w pamici podrcznej). Takie rozwizanie jest co prawda poprawne,
jednak jest mao prawdopodobne, by kiedykolwiek chcia uzyska wanie taki efekt, poniewa podstawow zalet techniki wstrzykiwania metod wyszukujcych jest moliwo
wstrzykiwania prototypw (niesingletonw), jak choby w analizowanym przykadzie. W tym
przypadku klasa WeatherServiceImpl i metoda getWeatherDao() s abstrakcyjne, moemy
jednak przykry dowoln metod zwracajc kadego komponentu JavaBean (w praktyce
metody kandydujce nie musz pobiera adnych argumentw, a ich nazwy nie musz
nawet by zgodne z konwencj nazewnictwa JavaBeans, cho ze wzgldu na klarowno
kodu takie rozwizanie jest zalecane). Warto pamita, e take pozostay kod aplikacji
musi korzysta z naszej metody zwracajcej (a nie z odpowiedniego pola) do uzyskiwania
dostpu do obiektu DAO. Wywoywanie metod zamiast bezporedniego odwoywania si
do pl obiektw jest jeszcze jedn dobr praktyk przetwarzania waciwoci komponentw
JavaBeans.
Stosujc techniki wstrzykiwania metod, warto odpowiedzie sobie na pytanie, jak mona
testowa kod (np. wykonywa testy jednostkowe) aplikacji bez kontenera, ktry wstrzykuje
dan metod. Podobne wtpliwoci s szczeglnie istotne w przypadku aplikacji podobnych do analizowanej usugi pogodowej, gdzie klasa implementacji jest abstrakcyjna. Stosunkowo prost i jednoczenie moliw do zrealizowania strategi przeprowadzania testw
jednostkowych w podobnych przypadkach jest stworzenie dla wspomnianej klasy abstrakcyjnej podklasy zawierajcej testow implementacj metody, ktra w normalnych warunkach jest wstrzykiwana, przykadowo:
...
WeatherService ws = new WeatherServiceImpl() {
protected WeatherDao getWeatherDao() {
// zwraca obiekt DAO dla danego testu
...
}
};
Stosowanie przez uytkownikw Springa tak zaawansowanych mechanizmw jak wstrzykiwanie metod zawsze powinno by poprzedzone dogbn analiz naley zdecydowa,
ktre rozwizanie w danej sytuacji jest najbardziej uzasadnione i ktre nie bdzie stanowio
niepotrzebnego utrudnienia dla programistw. Niezalenie od wynikw tej analizy naszym
zdaniem przedstawione powyej podejcie jest pod wieloma wzgldami lepsze od umieszczania w kodzie aplikacji zalenoci od interfejsw API kontenera.
88
89
89
90
90
91
Podstawowy kontener IoC Springa jest czsto nazywany fabryk komponentw (ang. bean
factory). Kada fabryka komponentw umoliwia logicznie spjne konfigurowanie i wizanie wielu obiektw za pomoc odpowiednich mechanizmw wstrzykiwania zalenoci.
Fabryka komponentw oferuje te pewne funkcje w zakresie zarzdzania obiektami, a w szczeglnoci ich cyklem ycia. Podejcie bazujce na technice odwracania kontroli umoliwia
daleko idce oddzielanie kodu poszczeglnych skadnikw aplikacji. Co wicej, poza korzystaniem z mechanizmu refleksji podczas uzyskiwania dostpu do obiektw odwracanie
kontroli uniezalenia kod aplikacji od samej fabryki komponentw i tym samym eliminuje konieczno dostosowywania kodu do wsppracy z funkcjami Springa. Kod aplikacji
potrzebny do konfigurowania obiektw (i do uzyskiwania obiektw z wykorzystaniem takich wzorcw jak singletony czy fabryki obiektw specjalnych) mona albo w caoci wyeliminowa, albo przynajmniej w znacznym stopniu zredukowa.
W typowej aplikacji bazujcej na Springu tylko bardzo niewielka ilo kodu scalajcego
bdzie wiadoma do wsppracy z kontenerem Springa lub korzystania z interfejsw
tego kontenera. Nawet t skromn ilo kodu w wielu przypadkach udaje si wyeliminowa, korzystajc z istniejcego kodu frameworka do zaadowania fabryki komponentw w sposb deklaratywny.
Fabryka komponentw
Istniej rne implementacje fabryki komponentw, z ktrych kada oferuje nieco inn
funkcjonalno (w praktyce rnice maj zwizek z dziaaniem mechanizmw konfiguracji,
a najczciej stosowan reprezentacj jest format XML). Wszystkie fabryki komponentw
implementuj interfejs org.springframework.beans.factory.BeanFactory programowe
zarzdzanie egzemplarzami wymaga dostpnoci wanie za porednictwem tego interfejsu.
Dodatkow funkcjonalno udostpniaj ewentualne podinterfejsy interfejsu BeanFactory.
Ponisza lista zawiera cz tej hierarchii interfejsw:
n BeanFactory
91
92
n ListableBeanFactory
n AutowireCapableBeanFactory
92
93
Oglnie Spring prbuje stosowa tzw. wyjtki nieweryfikowalne (ang. non-checked exceptions), czyli podklasy klasy RuntimePxception dla nieweryfikowalnych bdw. Interfejsy
fabryki komponentw, w tym BeanFactory i jego podinterfejsy, nie s pod tym wzgldem
wyjtkiem. W wikszoci przypadkw bdy konfiguracji s nieweryfikowalne, zatem
wszystkie wyjtki zwracane przez opisywane interfejsy API s podklasami klasy nieweryfikowalnych wyjtkw BeansPxception. Decyzja o tym, gdzie i kiedy naley przechwytywa
i obsugiwa te wyjtki, naley do programisty jeli istnieje odpowiednia strategia obsugi
sytuacji wyjtkowej, mona nawet podejmowa prby odtwarzania stanu sprzed wyjtku.
Kontekst aplikacji
Spring obsuguje te mechanizm znacznie bardziej zaawansowany od fabryki komponentw
tzw. kontekst aplikacji (ang. application context).
Warto podkreli, e kontekst aplikacji jest fabryk komponentw, a interfejs org.springframework.context.ApplicationContext jest podinterfejsem interfejsu BeanFactory.
Kompletn hierarchi interfejsw przedstawiono na rysunku 2.1.
93
94
Rysunek 2.1.
94
95
W tym i w wikszoci pozostaych rozdziaw tej ksiki analiza konfiguracji i funkcjonalnoci kontenera bdzie ilustrowana przykadami w wersji deklaratywnej, opartej na formacie XML (w tym XmlBeanFactory lub ClassPathXmlApplicationContext) fabryki komponentw i kontekstu aplikacji. Warto zda sobie spraw z tego, e funkcjonalno kontenera
w adnym razie nie jest tosama z formatem jego konfiguracji. Konfiguracja oparta na
XML jest co prawda wykorzystywana przez zdecydowan wikszo uytkownikw Springa,
jednak istnieje te kompletny interfejs API dla mechanizmw konfiguracji i dostpu do
kontenerw, w tym obsuga innych formatw konfiguracji (ktre mog by konstruowane
i obsugiwane w bardzo podobny sposb jak odpowiednie dokumenty XML). Przykadowo,
istnieje klasa PropertiesBeanDefinitionRearer, ktra odpowiada za zaadowanie do fabryki
komponentw definicji zapisanych w plikach waciwoci Javy.
Uruchamianie kontenera
Poprzednie przykady pokazay, jak mona programowo uruchamia kontener z poziomu
kodu uytkownika. W tym punkcie przeanalizujemy kilka ciekawych rozwiza w tym zakresie.
Egzemplarz (implementacj) interfejsu ApplicationContext mona wczyta, wskazujc
ciek do odpowiedniej klasy (pliku):
ApplicationContext appContext =
new ClassPathXmlApplicationContext("ch03/sample2/applicationContext.xml");
// Uwaga: ApplicationContext jest egzemplarzem BeanFactory, to oczywiste!
BeanFactory factory = (BeanFactory) appContext;
95
96
Uwani Czytelnicy zapewne zauwayli, e w porwnaniu z wczeniejszymi przykadami nieznacznie zmieniono sposb odwoywania si do komponentu weatherDao, ktry
wykorzystujemy jako waciwo komponentu usugi pogodowej; odwoania do komponentw szczegowo omwimy w dalszej czci rozdziau.
Aby wczyta i poczy oba fragmenty (teoretycznie moe ich by wicej), musimy je tylko
wymieni w tablicy nazw (acuchw) przekazywanej do konstruktora klasy ClassPathXmlApplicationContext:
ApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] {"applicationContext-services.xml",
"applicationContext-dao.xml"});
Abstrakcja Resource Springa (ktr szczegowo omwimy nieco pniej) umoliwia stosowanie prefiksu classpath*: do wyszczeglniania tych wszystkich zasobw pasujcych
do konkretnej nazwy, ktre s widoczne z perspektywy classloadera i jego classloaderw
nadrzdnych. Przykadowo, gdyby nasza aplikacja zostaa rozproszona pomidzy wiele plikw JAR, wszystkich nalecych do cieki do klas, z ktrych kady zawieraby wasny
fragment kontekstu aplikacji nazwany applicationContext.xml, moglibymy w prosty sposb okreli, e chcemy utworzy kontekst zoony ze wszystkich istniejcych fragmentw:
ApplicationContext appContext =
new ClassPathXmlApplicationContext("classpath*:applicationContext.xml"});
Okazuje si, e tworzenie i wczytywanie fabryki komponentw skonfigurowanych za pomoc odpowiednich zapisw jzyka XML jest bardzo atwe. Najprostszym rozwizaniem
jest uycie abstrakcji Resource Springa, ktra umoliwia uzyskiwanie dostpu do zasobw
wedug cieki klas:
ClassPathResource res =
new ClassPathResource("org/springframework/prospering/beans.xml"});
XmlBeanFactory factory = new XmlBeanFactory(res);
lub:
FilesystemResource res = new FilesystemResource("/some/file/path/beans.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
96
97
Aby wyczerpa ten temat, musimy wspomnie o moliwoci prostego oddzielenia operacji
tworzenia fabryki komponentw od procesu przetwarzania definicji komponentw. Nie bdziemy si zajmowa tym zagadnieniem w szczegach, warto jednak pamita, e takie
wyodrbnienie zachowania fabryki komponentw od mechanizmw przetwarzania definicji
komponentw upraszcza stosowanie innych formatw konfiguracji:
ClassPathResource res = new ClassPathResource("beans.xml"});
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(res);
danie od kontenera dostpu do komponentu wywouje proces jego tworzenia i inicjalizacji, ktry obejmuje omwion ju faz wstrzykiwania zalenoci. Krok wstrzykiwania zalenoci moe z kolei zainicjowa proces tworzenia pozostaych komponentw (zalenoci
pierwszego komponentu) itd., a do utworzenia kompletnego grafu wzajemnie powizanych egzemplarzy obiektw.
W zwizku z opisan procedur nasuwa si do oczywiste pytanie: co naleaoby zrobi
z sam fabryk komponentw lub kontekstem aplikacji, aby pozostay kod, ktry tego wymaga, mg uzyska do nich dostp? Obecnie skupiamy si na analizie sposobu konfigurowania i funkcjonowania kontenera, zatem przedstawienie i wyjanienie odpowiedzi na to
pytanie odmy na dalsz cz tego rozdziau.
97
98
Pamitaj, e z wyjtkiem bardzo niewielkiej iloci kodu scalajcego zdecydowana wikszo kodu aplikacji pisanego i czonego zgodnie z zaoeniami IoC nie musi zawiera
adnych operacji zwizanych z uzyskiwaniem dostpu do fabryki, poniewa za zarzdzanie zalenociami pomidzy obiektami i samymi obiektami odpowiada kontener.
Najprostsz strategi zapewniania odpowiednich proporcji pomidzy kodem scalajcym (niezbdnym do inicjowania pewnych dziaa) a waciwym kodem aplikacji jest
umieszczenie fabryki komponentw w znanym miejscu, ktre bdzie odpowiadao nie
tylko oczekiwanym zastosowaniom, ale te tym elementom kodu, ktre bd potrzeboway dostpu do tej fabryki. Sam Spring oferuje mechanizm deklaratywnego wczytywania kontekstu dla aplikacji internetowych i skadowania tego kontekstu w obiekcie
ServletContext. Co wicej, Spring zawiera klasy pomocnicze przypominajce singletony, ktre mog by z powodzeniem stosowane do skadowania i wydobywania z fabryki komponentw (jeli takie rozwizanie z jakiego powodu wydaje Ci si lepsze lub
jeli nie istnieje strategia skadowania fabryki komponentw w ramach konkretnej
aplikacji).
Prawidowe elementy i atrybuty pliku definicji szczegowo opisano w pliku XML DTD
(ang. Document Type Definition) nazwanym spring-beans.dtd. Wspomniany plik DTD
w poczeniu z podrcznikiem uytkownika Springa powinien by traktowany jak ostateczne
rdo informacji o technikach konfiguracji aplikacji. Oglnie, opcjonalne atrybuty elementu beans (na najwyszym poziomie elementw XML definicji komponentw) maj
wpyw na zachowanie caego pliku konfiguracji i zawieraj domylne wartoci dla rozmaitych aspektw wszystkich definiowanych komponentw, natomiast wikszo opcjonalnych
atrybutw i podelementw potomnych elementw bean opisuje konfiguracj i cykl ycia
poszczeglnych komponentw. Plik spring-beans.dtd jest co prawda doczany do Springa,
jednak z jego zawartoci mona si zapozna take w internecie (patrz www.springframework.org/dtd/spring-beans.dtd).
98
99
Identyfikator
W definicji komponentw na najwyszym poziomie hierarchii niemal we wszystkich przypadkach definiujemy jeden lub wiele identyfikatorw (lub nazw) komponentw, aby pozostae komponenty mogy si do nich odwoywa podczas programowego korzystania z danego kontenera. Do definiowania identyfikatorw (lub gwnych identyfikatorw)
komponentw suy atrybut ir. Zalet tego atrybutu jest zgodno z typem XML IDREF
kiedy pozostae komponenty bd si odwoyway do komponentu za porednictwem tak
zdefiniowanego identyfikatora, sam parser dokumentu XML moe pomc w sprawdzeniu,
czy takie odwoanie jest poprawne (czy w tym samym pliku zdefiniowano odpowiedni
identyfikator), zatem atrybut ir uatwia wczesn weryfikacj prawidowoci konfiguracji.
Warto jednak pamita, e typ XML IDREF wprowadza pewne ograniczenia w kwestii akceptowanych znakw identyfikatory musz si rozpoczyna od litery, a na kolejnych
pozycjach mog zawiera dowolne znaki alfanumeryczne i znaki podkrelenia (ale nie mog zawiera spacji). W wikszoci przypadkw opisane ograniczenia nie stanowi co
prawda adnego problemu, jeli jednak z jakiego powodu chcesz je omin, moesz zdefiniowa identyfikator w atrybucie name. Przykadowo, takie rozwizanie jest uzasadnione,
jeli identyfikator komponentu jest poza kontrol uytkownika i reprezentuje ciek URL.
Co wicej, atrybut name dopuszcza moliwo stosowania listy identyfikatorw oddzielonych przecinkami. Kiedy definicja komponentu definiuje wicej ni jeden identyfikator, np.
w formie kombinacji atrybutu ir i (lub) atrybutu name, wszystkie dodatkowe identyfikatory
(poza pierwszym) naley traktowa jak aliasy. Odwoania do wszystkich identyfikatorw
s rwnie poprawne. Przeanalizujmy kilka przykadw:
<beans<
<bean id="bean1" class="ch02.sample .TestBean"/<
<bean name="bean2" class="ch02.sample .TestBean"/<
<bean name="/myservlet/myaction" class="ch02.sample .TestBean"/<
<bean id="component1-dataSource"
name="component2-dataSource,component3-dataSource"
class="ch02.sample .TestBean"/<
</beans<
99
100
Tak zdefiniowana statyczna metoda fabrykujca moe zwraca egzemplarze obiektw dowolnego typu; klasa zwracanego egzemplarza nie musi by tosama z klas zawierajc
sam metod fabrykujc.
Trzecim mechanizmem tworzenia nowych egzemplarzy komponentu jest wywoywanie
niestatycznych metod fabrykujcych innych egzemplarzy komponentw w ramach tego
samego kontenera:
...
<bean id="nonStaticFactory" class="ch02.sample4.NonStaticFactory"/<
<bean id="testBeanObtainedViaNonStaticFactory"
factory-bean="nonStaticFactory" factory-method="getTestBeanInstance"/<
...
100
101
101
102
102
103
103
104
104
105
Analiza wspominanego ju dokumentu XML DTD pokazuje, e w ramach elementw property i constructor-arg mona stosowa wiele innych elementw. Kady z tych elementw definiuje jaki typ wartoci deklarowanej waciwoci lub argumentu konstruktora:
(bean | ref | idref | list | set | map | props | value | null)
Element ref suy do takiego ustawiania wartoci waciwoci lub argumentu konstruktora,
aby odwoywaa si do innego komponentu w ramach tej samej fabryki komponentw lub
w ramach jej fabryki nadrzdnej:
<ref local="weatherDao"/<
<ref bean="weatherDao"/<
<ref parent="weatherDao"/<
Atrybuty local, bean i parent wzajemnie si wykluczaj i musz zawiera identyfikator innego komponentu. W przypadku uycia atrybutu local analizator skadni dokumentu XML
moe zweryfikowa istnienie wskazanego komponentu ju na etapie analizy skadniowej.
Poniewa jednak cao bazuje na mechanizmie IDREF jzyka XML, komponent musi by
zdefiniowany w tym samym pliku XML co odwoanie do tego komponentu, a jego definicja musi wykorzystywa atrybut ir okrelajcy identyfikator, do ktrego bdziemy si odwoywali (zamiast atrybutu name). W przypadku uycia atrybutu bean wskazany komponent
moe si znajdowa w tym samym lub innym fragmencie dokumentu XML wykorzystywanym albo do budowy definicji fabryki komponentw, albo w definicji fabryki nadrzdnej wzgldem fabryki biecej. Za weryfikacj istnienia konkretnych komponentw moe
co prawda odpowiada sam Spring (nie analizator skadniowy XML), ale tylko wwczas,
gdy dana zaleno rzeczywicie musi zosta zrealizowana (a wic nie w czasie adowania
fabryki komponentw). Znacznie rzadziej stosowany atrybut parent okrela, e komponent
docelowy musi pochodzi z fabryki nadrzdnej wzgldem biecej fabryki komponentw.
Takie rozwizanie moe by przydatne w nieczstych sytuacjach, w ktrych wystpuje
konflikt nazw komponentw w biecej i nadrzdnej fabryce komponentw.
Element value suy do okrelania wartoci prostych waciwoci lub argumentw konstruktora. Jak ju wspominano, niezbdnym krokiem jest konwersja wartoci rdowej
(ktra ma posta acucha) na odpowiedni typ docelowej waciwoci lub argumentu konstruktora, czyli dowolny wbudowany typ skalarny, odpowiedni typ opakowania lub dowolny
inny typ, dla ktrego w kontenerze zarejestrowano implementacj interfejsu PropertyPritor
zdoln do obsugi tego typu. Przeanalizujmy teraz konkretny przykad:
<property name="classname"<
<value<ch02.sample6.StaticDataWeatherDaoImpl</value<
</property<
Powyszy fragment kodu ustawia waciwo typu String nazwan classname i przypisuje
mu sta warto ch02.sample6.StaticDataWeatherDaoImpl; gdyby jednak waciwo
classname bya typu java.lang.Class, fabryka komponentw musiaaby uy wbudowanej
(i automatycznie rejestrowanej) implementacji interfejsu PropertyPritor (w tym przypadku klasy ClassPritor) do konwersji tej wartoci acuchowej na egzemplarz obiektu klasy Class.
Istnieje moliwo stosunkowo prostego rejestrowania wasnych, niestandardowych implementacji interfejsu PropertyPritor, ktre bd obsugiway konwersj acuchw na
dowolne inne typy danych niezbdne do waciwej konfiguracji kontenera. Dobrym przykadem
105
106
Element irref jest wygodnym sposobem wychwytywania bdw w odwoaniach do innych komponentw za porednictwem wartoci acuchowych reprezentujcych ich nazwy.
Istnieje kilka komponentw pomocniczych samego Springa, ktre odwouj si do innych
komponentw (i wykonuj za ich pomoc pewne dziaania) wanie w formie wartoci
swoich waciwoci. Wartoci tego rodzaju waciwoci zwykle definiuje si w nastpujcy
sposb:
<property name="beanName"<<value<weatherService</value<</property<
106
107
<list<
<value<red</value<
<value<red</value<
<value<blue</value<
<ref local="curDate"/<
<list<
<value<one</value<
<value<two</value<
<value<three</value<
</list<
</list<
</property<
<property name="theSet"<
<set<
<value<red</value<
<value<red</value<
<value<blue</value<
</set<
</property<
<property name="theMap"<
<map<
<entry key="left"<
<value<right</value<
</entry<
<entry key="up"<
<value<down</value<
</entry<
<entry key="date"<
<ref local="curDate"/<
</entry<
</map<
</property<
<property name="theProperties"<
<props<
<prop key="left"<right</prop<
<prop key="up"<down</prop<
</props<
</property<
</bean<
<bean id="curDate" class="java.util.GregorianCalendar"/<
</beans<
Kolekcje typu List, Map i Set mog zawiera dowolne spord wymienionych poniej elementw:
(bean | ref | idref | list | set | map | props | value | null)
Jak pokazuje przedstawiony przykad listy, typy kolekcji mog by dowolnie zagniedane.
Warto jednak pamita, e waciwoci lub argumenty konstruktorw otrzymujce na wejciu
typy kolekcji musz by deklarowane za pomoc typw java.util.List, java.util.Set lub
java.util.Map. Nie moesz stosowa innych typw kolekcji (np. ArrayList), nawet jeli s
obsugiwane w Springu. Tego rodzaju ograniczenia mog stanowi powany problem, jeli
musimy zapewni warto dla waciwoci istniejcej klasy, ktra oczekuje okrelonego
107
108
108
109
dana klasa wykonuje jakie statyczne operacje inicjalizujce w czasie wczytywania. Przykadowo, sterowniki baz danych zwykle s rejestrowane w egzemplarzu interfejsu DriverManager biblioteki JDBC. Do rcznego okrelania zalenoci pomidzy komponentami suy atrybut repenrs-on, ktry wymusza utworzenie egzemplarza innego komponentu jeszcze
przed uzyskaniem dostpu do komponentu zalenego. Poniszy przykad pokazuje, jak
mona wymusza wczytywanie sterownika bazy danych:
<bean id="load-jdbc-driver" class="oracle.jdbc.driver.OracleDriver"/<
<bean id="weatherService" depends-on="load-jdbc-driver" class="..."<
...
</bean<
Warto pamita, e wikszo pul pocze z baz danych oraz klas pomocniczych Springa
(np. DriverManagerDataSource) korzysta z tego mechanizmu wymuszania wczytywania,
zatem powyszy fragment kodu jest tylko przykadem popularnego rozwizania.
n byName
109
110
n constructor
n autoretect
Istnieje moliwo ustawienia innego domylnego trybu automatycznego wizania zalenoci (innego ni no) dla wszystkich komponentw w danej fabryce wystarczy uy atrybutu refault-autowire w elemencie beans na najwyszym poziomie dokumentu XML.
Warto te pamita o moliwoci czenia technik automatycznego wizania z wizaniem
wprost, wwczas elementy definiujce zalenoci (property lub contructor-arg) maj wyszy priorytet od zalenoci wykrywanych automatycznie.
Sprawdmy teraz, jak mona uy mechanizmu automatycznego wizania zalenoci dla
naszej usugi pogodowej i jej obiektu DAO. Jak wida, moemy wyeliminowa z definicji
komponentu waciwo weatherDao i wczy automatyczne wizanie wedug nazw, a mimo
to Spring nadal bdzie w stanie odnale warto waciwoci wycznie w oparciu o dopasowanie jego nazwy. W tym przypadku moglibymy uy take trybu automatycznego
wizania zalenoci wedug typu, poniewa do typu naszej waciwo (WeatherDao) pasuje
tylko jeden komponent w kontenerze:
<beans<
<bean id="weatherService" autowire="byName"
class="ch02.sample2.WeatherServiceImpl"<
<!-- brak deklaracji waciwoci weatherDao --<
</bean<
110
111
111
112
albo dostarczy kontenerowi tak ilo informacji, ktra pozwoli mu waciwie przeprowadzi proces dopasowania w oparciu o typy danych wwczas powinnimy uy atrybutu
type okrelajcego typ danej wartoci:
<beans<
<bean id="errorBean" class="ch02.sampleX.ErrorBean"<
<constructor-arg type="int"<<value<1000</value<</constructor-arg<
<constructor-arg type="java.lang.String"<
<value<Nieoczekiwany bd</value<
</constructor-arg<
</bean<
</beans<
n simple
n objects
n all
112
113
Pamitaj te, e take interfejs wywoa zwrotnych InitializingBean (patrz nastpny punkt)
moe by wykorzystywany do rcznego sprawdzania poprawnoci zalenoci.
Opis
Inicjalizacja
rozpoczynajca si
w momencie utworzenia
egzemplarza komponentu
Wstrzyknicie zalenoci
Wywoanie metody
setBeanName()
Wywoanie metody
setBeanFactory()
Wywoanie metody
setResourceLoader()
113
114
Opis
Wywoanie metody
setApplicationEventPublisher()
Wywoanie metody
setMessageSource()
Wywoanie metody
setApplicationContext()
Przekazanie
postprocesorom
komponentu wywoania
zwrotnego przed
inicjalizacj
Wywoanie metody
afterPropertiesSet()
114
Wywoanie
zadeklarowanej metody
inicjalizujcej
Przekazanie postprocesorom
komponentu wywoania
zwrotnego po inicjalizacji
z argumentem zawierajcym
egzemplarz komponentu
Uycie komponentu
115
Akcja
Opis
Rozpoczcie procedury
destrukcji komponentu
Przekazanie
postprocesorom
komponentu wywoania
zwrotnego zniszcz
Wywoanie metody
destroy()
Wywoanie
zadeklarowanej metody
niszczcej
115
116
116
117
Kiedy wdroymy taki obiekt DAO w postaci komponentu wewntrz kontenera Springa, bdziemy mogli skorzysta z uatwie (przede wszystkim mechanizmw wstrzykiwania przez
metody ustawiajce i wstrzykiwania przez konstruktor) w zakresie dostarczania wszystkich
wartoci wymaganych przez sterownik JDBC do nawizania poczenia, czyli adresu URL,
nazwy uytkownika i hasa. Nie mamy jednak zamiaru tworzy puli pocze (niezalenie
od tego, czy bdziemy korzysta ze rodowiska J2EE czy z mniej zaawansowanego kontenera); nasze poczenie w zaoeniu nie ma podlega adnym procedurom zarzdzania
transakcjami (znanym z kontenera J2EE i stosowanym tylko w przypadku pocze zarzdzanych przez kontener).
Do oczywistym rozwizaniem w kwestii uzyskiwania niezbdnych pocze jest uycie
implementacji interfejsu DataSource wprowadzonych w JDBC 2.0. Kiedy nasz obiekt DAO
bdzie ju zawiera egzemplarz takiej implementacji, wystarczy e zada odpowiedniego
poczenia (faktyczna realizacja tego dania nastpuje gdzie indziej). Teoretyczna dostpno egzemplarza DataSource nie stanowi problemu, poniewa wiemy, e istniej takie niezalene, autonomiczne implementacje puli pocze jak Apache Jakarta Commons DBCP,
ktre mona z powodzeniem stosowa w rodowiskach J2SE oraz J2EE i ktre s udostpniane za porednictwem interfejsu DataSource; wiemy take, e podobne mechanizmy zarzdzania pul pocze na poziomie kontenera (bdce czci szerszych rozwiza w zakresie zarzdzania transakcjami) s dostpne w wikszoci rodowisk kontenerowych J2EE,
gdzie take maj posta implementacji interfejsu DataSource.
117
118
118
119
<value<oracle.jdbc.driver.OracleDriver</value<
</property<
<property name="url"<
<value<jdbc:oracle:thin:@db-server:1 21:devdb</value<
</property<
<property name="username"<<value<john</value<</property<
<property name="password"<<value<password</value<</property<
</bean<
<bean id="weatherDao" class="ch02.sampleX.JdbcWeatherDaoImpl"<
<property name="dataSource"<
<ref bean="dataSource"/<
</property<
</bean<
Warto si jeszcze zastanowi nad sposobem wymiany wykorzystywanej implementacji interfejsu DataSource (w tym przypadku DBCP) na inn (np. uzyskiwan ze rodowiska JNDI).
Wyglda na to, e rozwizanie tego problemu nie bdzie atwe, poniewa poza ustawieniem w naszym obiekcie DAO waciwoci typu DataSource musimy otrzyma odpowiedni warto JNDI na razie wiemy tylko, jak przygotowywa konfiguracj kontenera, aby
definiowaa waciwoci JavaBean zawierajce konkretne wartoci lub odwoania do innych
komponentw. Okazuje si, e realizacja tego zadania wcale nie wymaga wielkich umiejtnoci; wystarczy uy klasy pomocniczej nazwanej JnriObjectFactoryBean:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"<
<property name="jndiName"<
<value<java:comp/env/jdbc/datasource</value<
</property<
</bean<
<bean id="weatherDao" class="ch02.sampleX.JdbcWeatherDaoImpl"<
<property name="dataSource"<
<ref bean="dataSource"/<
</property<
</bean<
119
120
n TransactionProxyFactoryBean
120
121
n RmiProxyFactoryBean
n LocalSessionFactoryBean
n LocalStatelessSessionProxyFactoryBean i SimpleRemoteStatelessSessionProxyFactoryBean
121
122
Skoro moemy w sposb transparentny, przezroczysty (przynajmniej z perspektywy klienta) uzyskiwa dostp do zdalnych usug za porednictwem takich technologii jak RMI,
RPC przez HTTP czy EJB, niby dlaczego nie mielibymy wdraa cakowicie niezalenych
rozwiza, i po co w ogle wiza kod klienta z jedn implementacj ponad inn tam, gdzie
nie jest to konieczne? W rozwizaniach platformy J2EE mona zaobserwowa tendencj do
udostpniania takich zasobw jak implementacje DataSource, zasoby JMS czy interfejsy
JavaMail za porednictwem JNDI. Nawet jeli ten sposb udostpniania zasobw znajduje
jakie uzasadnienie, bezporedni dostp klienta do rodowiska JNDI jest cakowicie sprzeczny
z zaoeniami efektywnego wytwarzania oprogramowania. Budowa dodatkowej warstwy
abstrakcji np. za pomoc klasy JnriObjectFactoryBean oznacza, e w przyszoci bdzie
mona zmieni rodowisko na inne ni JNDI bez koniecznoci modyfikowania kodu
klienta (odpowiednio dostosowujc wycznie konfiguracj samej fabryki komponentw).
Nawet jeli nie planujesz zmiany rodowiska wdroeniowego ani technologii implementacji ju po wdroeniu oprogramowania w docelowym rodowisku, moesz by pewien, e
taka abstrakcja znacznie uatwi testy jednostkowe i testy integracyjne, poniewa umoliwi
weryfikacj rnych konfiguracji wdroe i scenariuszy testowych. Tym zagadnieniom powicimy wicej miejsca w nastpnym rozdziale. Warto te podkreli, e stosujc komponent
JnriObjectFactoryBean, eliminujemy potrzeb pisania zaawansowanego kodu w obiekcie
DAO (konkretnie wyszukiwania obiektu w rodowisku JNDI), ktry nie miaby nic wsplnego z waciw funkcjonalnoci biznesow tego obiektu. Ten przykad dobrze pokazuje,
jak stosowanie techniki wstrzykiwania zalenoci ogranicza zoono i niead w kodzie
rdowym aplikacji.
122
123
Jednym z najprostszych sposobw osignicia tego celu jest deklaratywne opakowanie takiego obiektu, aby nabra cech obiektu transakcyjnego (np. za pomoc komponentu fabrykujcego Springa nazwanego TransactionProxyFactoryBean):
<bean id="weatherServiceTarget" class="ch02.sample2.WeatherServiceImpl"<
<property name="weatherDao"<
<ref local="weatherDao"/<
</property<
</bean<
<!-- porednik transakcyjny -->
<bean id="weatherService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"<
<property name="target"<<ref local="weatherServiceTarget"/<</property<
<property name="transactionManager"<<ref local="transactionManager"/<</property<
<property name="transactionAttributes"<
<props<
<prop key="*"<PROPAGATION_REQUIRED</prop<
</props<
</property<
</bean<
Jeli na tym etapie nie do koca rozumiesz, jak naley szczegowo konfigurowa komponent TransactionProxyFactoryBean lub jak ten komponent faktycznie dziaa, nie masz powodw do zmartwie. Istotne jest to, e wspomniany komponent jest implementacj interfejsu FactoryBean, ktra dla otrzymanego na wejciu komponentu docelowego generuje
obiekt transakcyjnego porednika (z jednej strony implementujcy te same interfejsy co
komponent docelowy, z drugiej strony obsugujcy dodatkow semantyk przetwarzania
transakcyjnego). Poniewa chcemy, aby kod kliencki wykorzystywa obiekt opakowania,
nazwa oryginalnego (nieopakowanego i nietransakcyjnego) komponentu jest zmieniana (rozszerzana o sufiks Target), a jego pierwotn nazw otrzymuje wygenerowany komponent transakcyjny (w tym przypadku bd to odpowiednio weatherServiceTarget i weatherService).
Oznacza to, e istniejcy kod kliencki, ktry korzysta z usugi pogodowej, w ogle nie wie,
e od momentu zmiany konfiguracji korzysta z usugi transakcyjnej.
Opisany mechanizm deklaratywnego opakowywania obiektw jest co prawda bardzo wygodny (szczeglnie w zestawieniu z rozwizaniem alternatywnym, czyli dziaaniami programowymi na poziomie kodu), jednak w przypadku wikszych aplikacji z dziesitkami
lub setkami interfejsw usug, ktre wymagaj stosowania bardzo podobnych technika
opakowywania, wielokrotne definiowanie niemal identycznego, szablonowego kodu XML
wydaje si strat czasu. Okazuje si, e wprost idealnym rozwizaniem tego problemu jest
oferowana przez kontener obsuga definicji zarwno macierzystych, jak i potomnych komponentw. Korzystajc z dobrodziejstw tego mechanizmu, moemy w prosty sposb zdefiniowa abstrakcyjny, macierzysty (szablonowy) porednik transakcyjny:
<bean id="txProxyTemplate" abstract="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"<
<property name="transactionManager"<
<ref local="transactionManager"/<
</property<
<property name="transactionAttributes"<
123
124
Istnieje moliwo skorzystania z jeszcze bardziej klarownej i zwizej formy dziedziczenia. Poniewa aden z klientw nigdy nie bdzie potrzebowa dostpu do nieopakowanego
komponentu naszej usugi pogodowej, mona go zdefiniowa jako komponent wewntrzny
wzgldem porednika, ktry go opakowuje:
<bean id="weatherService" parent="txProxyTemplate"<
<property name="target"<
<bean class="ch02.sample2.WeatherServiceImpl"<
<property name="weatherDao"<
<ref local="weatherDao"/<
</property<
</bean<
</property<
</bean<
Jeli jaka inna usuga bdzie wymagaa podobnego opakowania, programista bdzie mg
uy definicji komponentu, ktra w bardzo podobny sposb odziedziczy waciwoci macierzystego szablonu. W poniszym przykadzie odziedziczona waciwo transactionAttributes jest dodatkowo przykrywana w ten sposb wprowadzono nowe (waciwe
dla danego porednika) ustawienia propagowania transakcji:
<bean id="anotherWeatherService" parent="txProxyTemplate"<
<property name="target"<
<bean class="ch02.sampleX.AnotherWeatherServiceImpl"/<
</property<
<property name="transactionAttributes"<
<props<
<prop key="save*"<PROPAGATION_REQUIRED</prop<
<prop key="*"<PROPAGATION_REQUIRED,readOnly</prop<
</props<
</property<
</bean<
124
125
Jeszcze prostszym rozwizaniem jest skorzystanie z mechanizmu automatycznego poredniczenia (ang. autoproxying) programowania aspektowego, ktry automatycznie
wykrywa wszelkie cechy wsplne porad AOP w definicjach rnych komponentw. Wicej
informacji na ten temat znajdziesz w rozdziale 4.
125
126
Stosowanie postprocesorw
do obsugi niestandardowych komponentw i kontenerw
Postprocesory komponentw s w istocie specjalnymi obiektami nasuchujcymi (ang.
listeners), ktre mona rejestrowa (wprost lub niejawnie) w kontenerze i ktre otrzymuj
ze strony kontenera wywoania zwrotne dla kadego komponentu, dla ktrego ten kontener
tworzy egzemplarz. Postprocesory fabryk komponentw s bardzo podobne do postprocesorw komponentw z t rnic, e otrzymuj wywoania zwrotne w momencie utworzenia
egzemplarza samego kontenera. W sytuacji, gdy konieczne jest regularne dostosowywanie
do zmieniajcych si warunkw konfiguracji komponentu, grupy komponentw lub caego
kontenera, mona to zadanie bardzo uatwi, tworzc wasny postprocesor lub korzystajc
z jednego z wielu istniejcych postprocesorw doczanych do Springa.
Postprocesory komponentw
Postprocesory komponentw implementuj interfejs BeanPostProcessor:
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException;
}
W przedstawionej w tym rozdziale tabeli zdarze skadajcych si na cykl ycia komponentw do precyzyjnie wskazano punkty, w ktrych nastpuj poszczeglne wywoania
zwrotne. Sprbujmy teraz stworzy postprocesor komponentw, ktry bdzie wykorzystywa wywoanie zwrotne metody postProcessAfterInitialization() do wypisywania na
konsoli nazwy kadego komponentu, dla ktrego w danym kontenerze utworzono egzemplarz (wywoanie bdzie nastpowao bezporednio po zdarzeniu utworzenia egzemplarza):
public class BeanInitializationLogger implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
126
127
Kiedy skonfigurowany w ten sposb kontekst aplikacji zostanie zaadowany, nasz postprocesor otrzyma dwa wywoania zwrotne i w odpowiedzi wygeneruje (wywietli na konsoli)
nastpujce dane wyjciowe:
Zainicjalizowano komponent 'weatherDao'
Zainicjalizowano komponent 'weatherService'
Stosowanie postprocesorw komponentw dla nawet stosunkowo prostych fabryk komponentw jest nieco bardziej skomplikowane ni w przypadku kontekstw aplikacji, poniewa wymaga rcznego rejestrowania (co jest zgodne z duchem fabryk komponentw, ktry
przewiduje bardziej programowe podejcie), zamiast samego zadeklarowania postprocesora
w formie komponentu w pliku konfiguracyjnym XML:
XmlBeanFactory factory =
new XmlBeanFactory(new ClassPathResource("ch02/sample8/beans.xml"));
BeanInitializationLogger logger = new BeanInitializationLogger();
factory.addBeanPostProcessor(logger);
// Poniewa nasze komponenty s singletonami, bd podlegay fazie wstpnego tworzenia egzemplarzy
// (take wwczas postprocesor otrzyma odpowiednie wywoania zwrotne).
factory.preInstantiateSingletons();
127
128
Postprocesor PropertyPlaceholderConfigurer
Podczas wdraania aplikacji bazujcych na Springu czsto si okazuje, e wikszo elementw konfiguracji kontenera nie bdzie modyfikowana w czasie wdraania. Zmuszanie
kogokolwiek do przeszukiwania skomplikowanych plikw konfiguracyjnych tylko po to,
by zmieni kilka wartoci, ktre tego rzeczywicie wymagaj, bywa bardzo niewygodne.
Takie rozwizanie stwarza te niebezpieczestwo popenienia przypadkowego bdu w pliku
konfiguracyjnym, np. przez nieumylne zmodyfikowanie niewaciwej wartoci.
PropertyPlaceholrerConfigurer jest postprocesorem fabryki komponentw, ktry uyty
w definicji fabryki komponentw lub kontekstu aplikacji umoliwia okrelanie pewnych
wartoci za porednictwem specjalnych acuchw zastpczych, acuchw-wypeniaczy (ang.
placeholder strings), ktre s nastpnie zastpowane przez rzeczywiste wartoci pochodzce
128
129
Aby uy teraz zadeklarowanego przed chwil komponentu konfiguratora dla prostej fabryki komponentw, naley go uruchomi rcznie:
XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setLocation(new FileSystemResource("db.properties"));
ppc.postProcessBeanFactory(factory);
Postprocesor PropertyOverrideConfigurer
PropertyOverrireConfigurer, ktry take jest postprocesorem fabryk komponentw, co
prawda pod wieloma wzgldami przypomina postprocesor PropertyPlaceholrerConfigurer,
jednak o ile w przypadku tego drugiego wartoci musiay pochodzi z zewntrznego pliku
129
130
W ten sposb mona przykry cztery waciwoci komponentu rataSource. Wszelkie waciwoci (wszystkich komponentw) w danym kontenerze, ktre nie zostay przykryte przez
nowe wartoci przedstawionego pliku waciwoci, utrzymaj swoje dotychczasowe wartoci albo te zdefiniowane w konfiguracji kontenera, albo wartoci domylne komponentu
(w przypadku braku odpowiednich zapisw w pliku konfiguracyjnym). Poniewa sama
analiza konfiguracji kontenera nie pozwala okreli, czy dana warto zostanie przykryta
(dla pewnoci konieczne jest jeszcze przestudiowanie pliku waciwoci), tego typu funkcjonalno naley wykorzystywa tylko w uzasadnionych przypadkach.
Postprocesor CustomEditorConfigurer
CustomPritorConfigurer jest postprocesorem fabryki komponentw, za pomoc ktrego
moemy rejestrowa wasne edytory waciwoci (rozszerzenia klasy PropertyPritorSupport)
komponentw JavaBeans obsugujce konwersj wartoci acuchowych na docelowe
wartoci waciwoci lub argumentw konstruktora (w konkretnym, czsto zoonym formacie obiektowym).
130
131
Pena dokumentacja tej klasy w formacie JavaDoc jest doczana do wersji instalacyjnej
Springa. Implementacj wasnego edytora waciwoci najlepiej rozpocz od rozszerzenia
pomocniczej klasy bazowej java.beans.PropertyPritorSupport bdcej czci standardowej biblioteki klas Javy. Wspomniana klasa implementuje wikszo potrzebnych mechanizmw edycji waciwoci (take poza standardowymi metodami setAsText() i getAsText(), ktrych implementacje zawsze musimy przykrywa). Warto pamita, e chocia
egzemplarze PropertyPritor maj swj stan i w normalnych warunkach nie gwarantuj
bezpieczestwa przetwarzania wielowtkowego, sam Spring zapewnia odpowiednie mechanizmy synchronizacji caej sekwencji wywoa metod niezbdnych do prawidowego
przeprowadzania konwersji.
CustomDatePritor moe korzysta z dowolnej (przekazywanej za porednictwem argumentu
jej konstruktora) implementacji interfejsu java.text.DateFormat do przeprowadzania waciwej implementacji. Wdraajc klas CustomDatePritor, moesz uy implementacji
java.text.SimpleDateFormat. Nasz edytor waciwoci mona te skonfigurowa w taki sposb, aby acuchy puste albo interpretowa jak wartoci null, albo traktowa jak bd nie-
prawidowego argumentu.
131
132
Postprocesor BeanNameAutoProxyCreator
BeanNameAutoProxyCreator jest postprocesorem komponentw. Co prawda techniki korzy-
stania z tego postprocesora omwimy bardziej szczegowo w rozdziale powiconym programowaniu aspektowemu, jednak ju teraz dobrze jest wiedzie o jego istnieniu. Najkrcej
mwic, dla danej na wejciu listy nazw komponentw postprocesor BeanNameAutoProxyCreator moe opakowa te spord otrzymanych komponentw danej fabryki, ktrych nazwy pasuj do nazw znajdujcych si na tej licie (proces opakowywania nastpuje w czasie tworzenia egzemplarzy komponentw, a zadaniem obiektw poredniczcych jest albo
przechwytywanie operacji dostpu do oryginalnych komponentw, albo modyfikowanie
ich zachowa).
132
133
Postprocesor DefaultAdvisorAutoProxyCreator
Ten postprocesor komponentw przypomina opisany przed chwil postprocesor BeanNameAutoProxyCreator, jednak oprcz samych nazw komponentw przeznaczonych do opakowania odnajduje te informacje na temat sposobu tego opakowania (tzw. porady). Take w tym
przypadku warto si zapozna z treci rozdziau powiconego technikom programowania
aspektowego (AOP).
Jak dziki funkcjom kontenera mona korzysta z zalet jednego, logicznie spjnego
i przewidywalnego mechanizmu dostpu, konfigurowania i wizania obiektw
(zamiast uywa programowych lub tworzonych naprdce mechanizmw czenia
klas, ktre tylko utrudniaj testowanie). Oglnie, kontener pozwala cakowicie
wyeliminowa konieczno korzystania z niestandardowych, przystosowanych
do konkretnych klas fabryk komponentw oraz singletonw.
133