You are on page 1of 64

IDZ DO

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

Struktura szkieletu Spring


Tworzenie komponentw i definiowanie zalenoci pomidzy nimi
Testowanie aplikacji i testy jednostkowe
Programowanie aspektowe w Spring
Poczenia z relacyjnymi bazami danych za pomoc JDBC
Zarzdzanie transakcjami
Korzystanie z mechanizmu Hibernate
Zabezpieczanie aplikacji
Stosowanie szkieletu Web MVC
Przekonaj si, jak Spring moe zmieni Twoj prac nad tworzeniem aplikacji J2EE

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

Rozdzia 2. Fabryka komponentw i kontekst aplikacji ......................................................................... 81


Odwracanie kontroli i wstrzykiwanie zalenoci .............................................................. 82
Rne formy wstrzykiwania zalenoci ..................................................................... 85
Wybr pomidzy wstrzykiwaniem przez metody ustawiajce
a wstrzykiwaniem przez konstruktory ..................................................................... 89

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\!!!spis.doc

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


Kontener .................................................................................................................... 91
Fabryka komponentw ........................................................................................... 91
Kontekst aplikacji .................................................................................................. 93
Uruchamianie kontenera ........................................................................................ 95
Korzystanie komponentw uzyskiwanych z fabryki ..................................................... 97
Konfiguracja komponentw w formacie XML ............................................................. 98
Podstawowa definicja komponentu .......................................................................... 99
Definiowanie zalenoci komponentw .................................................................. 102
Zarzdzanie cyklem ycia komponentu ................................................................... 113
Abstrakcja dostpu do usug i zasobw ................................................................. 116
Wielokrotne wykorzystywanie tych samych definicji komponentw ............................ 122
Stosowanie postprocesorw do obsugi niestandardowych komponentw i kontenerw .. 126
Podsumowanie ......................................................................................................... 133

Rozdzia 3. Zaawansowane mechanizmy kontenera ...........................................................................135


Abstrakcje dla niskopoziomowych zasobw ................................................................. 136
Kontekst aplikacji jako implementacja interfejsu ResourceLoader ............................ 136
Kontekst aplikacji jako rdo komunikatw ........................................................... 139
Zdarzenia aplikacji .................................................................................................... 142
Zarzdzanie kontenerem ............................................................................................ 145
cieki lokalizacji zasobw przekazywane do konstruktorw implementacji
interfejsu ApplicationContext .............................................................................. 145
Deklaratywne korzystanie z kontekstw aplikacji .................................................... 147
Podzia definicji kontenera na wiele plikw ............................................................. 149
Strategie obsugi moduw ................................................................................... 151
Singletony obsugujce dostp do kontenera ......................................................... 154
Pomocnicze komponenty fabrykujce .......................................................................... 155
Komponent PropertyPathFactoryBean .................................................................... 155
Komponent FieldRetrievingFactoryBean ................................................................. 156
Komponent MethodInvokingFactoryBean ................................................................ 157
Edytory waciwoci oferowane w ramach Springa ........................................................ 158
Strategie testowania ................................................................................................. 159
Testy jednostkowe ............................................................................................... 160
Testy wykorzystujce kontener Springa .................................................................. 163
Rozwizania alternatywne wzgldem konfiguracji w formacie XML ................................. 166
Definicje konfiguracji w plikach waciwoci ........................................................... 166
Programowe definicje komponentw ...................................................................... 168
Pozostae formaty ................................................................................................ 168
Materiay dodatkowe ................................................................................................. 169
Podsumowanie ......................................................................................................... 169

Rozdzia 4. Spring i AOP ...........................................................................................................................171


Cele ......................................................................................................................... 171
Zaoenia ................................................................................................................. 173
Przykad ................................................................................................................... 173
Framework programowania aspektowego Springa ........................................................ 177
acuch przechwytywania ..................................................................................... 178
Zalety i wady ....................................................................................................... 178
Rada .................................................................................................................. 180
Przecicia ........................................................................................................... 186

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\!!!spis.doc

Spis treci

Doradcy .............................................................................................................. 193


Integracja z kontenerem IoC Springa ..................................................................... 195
Analizowanie i zmiana stanu porednika w czasie wykonywania programu ................ 212
Programowe tworzenie porednikw ...................................................................... 213
Korzystanie z zaawansowanych funkcji Spring AOP ....................................................... 214
rda obiektw docelowych ................................................................................. 214
Wczesne koczenie acucha przechwytywania ....................................................... 221
Stosowanie wprowadze ...................................................................................... 221
Udostpnianie biecego porednika .................................................................... 224
Udostpnianie biecego egzemplarza interfejsu MethodInvocation ......................... 225
Zrozumienie typw porednikw ............................................................................ 226
Diagnozowanie i testowanie .................................................................................. 228
Rozmaitoci ........................................................................................................ 231
Integracja z innymi frameworkami programowania aspektowego ................................... 234
Cele ................................................................................................................... 235
Integracja z narzdziem AspectJ ............................................................................ 235
AspectWerkz ....................................................................................................... 242
Materiay dodatkowe ................................................................................................. 243
Podsumowanie ......................................................................................................... 243

Rozdzia 5. Obiekty DAO i framework Spring JDBC .............................................................................245


Wzorzec obiektw dostpu do danych ......................................................................... 246
Wprowadzenie do Spring JDBC ................................................................................... 248
Motywacja problemy bezporedniego korzystania z interfejsu JDBC ...................... 248
W czym moe pomc Spring? ................................................................................ 251
Prosty przykad .................................................................................................... 251
Budowa warstwy dostpu do danych dla przykadowej aplikacji ..................................... 253
Model danych stosowany w przykadowej aplikacji .................................................. 253
rdo danych ...................................................................................................... 254
Tumaczenie wyjtkw .......................................................................................... 256
Operacje klasy JdbcTemplate ..................................................................................... 259
Stosowanie metod zwrotnych ................................................................................ 259
Metody pomocnicze klasy JdbcTemplate ................................................................ 261
Wykonywanie prostych zapyta za porednictwem klasy JdbcTemplate ..................... 262
Wykonywanie prostych aktualizacji za porednictwem klasy JdbcTemplate ................ 263
Zaawansowane zastosowania klasy JdbcTemplate ................................................. 264
Obsuga interfejsu RowSet ................................................................................... 266
Klasy obsugujce operacje na relacyjnych systemach zarzdzania bazami danych ......... 267
Klasy SqlQuery i MappingSqlQuery ........................................................................ 268
Operacje wstawiania i aktualizacji realizowane za pomoc klasy SqlUpdate .............. 271
Aktualizowanie zbioru wynikowego za pomoc klasy UpdateSqlQuery ....................... 272
Generowanie kluczy gwnych ............................................................................... 273
Uzyskiwanie kluczy wygenerowanych przez baz danych .......................................... 274
Wywoywanie procedur skadowanych .................................................................... 275
Zagadnienia zaawansowane ....................................................................................... 278
Uruchamianie Spring JDBC na serwerze aplikacji .................................................... 278
Stosowanie niestandardowych mechanizmw tumaczenia wyjtkw ........................ 280
Odczytywanie i zapisywanie danych obiektw LOB .................................................. 284
Aktualizacje wsadowe .......................................................................................... 289
Zaawansowane techniki korzystania z procedur skadowanych ................................. 290

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\!!!spis.doc

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


Zagadnienia dodatkowe ............................................................................................. 295
Wydajno .......................................................................................................... 295
Kiedy naley uywa biblioteki JDBC,
a kiedy narzdzi odwzorowa obiektowo-relacyjnych? ........................................... 296
Wersje biblioteki JDBC i platformy J2EE ................................................................. 296
Podsumowanie ......................................................................................................... 297

Rozdzia 6. Zarzdzanie transakcjami i rdami danych .................................................................299


Pojcia podstawowe .................................................................................................. 299
Czym jest transakcja? .......................................................................................... 300
Waciwoci ACID ................................................................................................ 300
Sterowanie wspbienoci ................................................................................. 303
Transakcje i platforma J2EE ....................................................................................... 303
Transakcje lokalne ............................................................................................... 304
Transakcje globalne (rozproszone) ........................................................................ 304
Propagowanie transakcji ....................................................................................... 305
Wyznaczanie granic pomidzy transakcjami ............................................................ 305
Przykad obsugi transakcji w Springu .......................................................................... 306
Wprowadzenie do oferowanej przez Spring warstwy abstrakcji ponad transakcjami ......... 308
Przegld moliwych opcji sterowania transakcjami .................................................. 310
Definicja transakcji .............................................................................................. 312
Status transakcji ................................................................................................. 314
Strategie wyznaczania granic transakcji ................................................................. 314
Strategie zarzdzania transakcjami ....................................................................... 328
Deklaracje rde danych ........................................................................................... 338
rda lokalne bez puli ......................................................................................... 338
rda lokalne z pul ............................................................................................ 339
JNDI ................................................................................................................... 340
Wybr pomidzy lokalnym rdem danych a rdem danych JNDI ........................... 341
Podsumowanie ......................................................................................................... 341

Rozdzia 7. Odwzorowania obiektowo-relacyjne ................................................................................343


Pojcia podstawowe .................................................................................................. 344
Podstawy odwzorowa obiektowo-relacyjnych ......................................................... 345
Obiektowe jzyki zapyta ...................................................................................... 346
Przezroczyste utrwalanie ....................................................................................... 347
Kiedy naley korzysta z narzdzi odwzorowa obiektowo-relacyjnych? ..................... 348
Obsuga odwzorowa obiektowo-relacyjnych w Springu ................................................. 349
Obiekty dostpu do danych (DAO) ......................................................................... 349
Zarzdzanie transakcjami ..................................................................................... 350
iBATIS SQL Maps ...................................................................................................... 351
Plik odwzorowania ............................................................................................... 352
Implementacja interfejsu DAO ............................................................................... 354
Konfiguracja w kontekcie Springa ........................................................................ 356
Zarzdzanie transakcjami ..................................................................................... 357
Podsumowanie analizy narzdzia iBATIS ................................................................ 359
Hibernate ................................................................................................................. 360
Plik odwzorowa .................................................................................................. 362
Implementacja interfejsu DAO ............................................................................... 363
Konfiguracja w kontekcie Springa ........................................................................ 366
Zarzdzanie transakcjami ..................................................................................... 370

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\!!!spis.doc

Spis treci

Otwarta sesja w widoku ........................................................................................ 377


Obsuga obiektw BLOB i CLOB ............................................................................ 381
Hibernate: podsumowanie .................................................................................... 383
JDO ......................................................................................................................... 385
Cykl ycia trwaego obiektu ................................................................................... 386
Implementacje interfejsw DAO ............................................................................ 387
Konfiguracja kontekstu aplikacji Springa ................................................................ 389
Zarzdzanie transakcjami ..................................................................................... 391
Cykl ycia egzemplarza PersistenceManager .......................................................... 392
Otwarty egzemplarz PersistenceManager w widoku ................................................. 393
Dialekt JDO ......................................................................................................... 396
Podsumowanie analizy technologii JDO .................................................................. 397
Pozostae narzdzia odwzorowa obiektowo-relacyjnych ............................................... 399
Apache OJB ......................................................................................................... 399
TopLink ............................................................................................................... 401
Cayenne ............................................................................................................. 403
Specyfikacja JSR-220 ........................................................................................... 403
Podsumowanie ......................................................................................................... 404

Rozdzia 8. Lekki framework zdalnego dostpu ..................................................................................407


Pojcia podstawowe i zakres tematyczny rozdziau ....................................................... 408
Jednolity styl konfiguracji ........................................................................................... 410
Hessian i Burlap ....................................................................................................... 412
Uzyskiwanie dostpu do usugi ............................................................................. 414
Eksportowanie usugi ........................................................................................... 416
Obiekt wywoujcy HTTP ............................................................................................. 417
Uzyskiwanie dostpu do usugi ............................................................................. 419
Eksportowanie usugi ........................................................................................... 420
Opcje konfiguracyjne ............................................................................................ 421
RMI ......................................................................................................................... 422
Uzyskiwanie dostpu do usugi ............................................................................. 424
Strategie wyszukiwania piekw ........................................................................... 426
Eksportowanie usugi ........................................................................................... 428
Opcje konfiguracyjne ............................................................................................ 429
RMI-IIOP .............................................................................................................. 429
Usugi sieciowe przez JAX-RPC ................................................................................... 430
Uzyskiwanie dostpu do usugi ............................................................................. 432
Eksportowanie usugi ........................................................................................... 435
Niestandardowe odwzorowania typw .................................................................... 437
Podsumowanie ......................................................................................................... 439

Rozdzia 9. Usugi wspomagajce .........................................................................................................443


JMS ......................................................................................................................... 443
Wprowadzenie ..................................................................................................... 444
Cele obsugi JMS w Springu .................................................................................. 445
Dostp do JMS za pomoc szablonu ..................................................................... 446
Obsuga wyjtkw ................................................................................................ 449
Zarzdzanie obiektem ConnectionFactory .............................................................. 449
Konwertery komunikatw ...................................................................................... 450
Zarzdzanie miejscami docelowymi ....................................................................... 451

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\!!!spis.doc

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


Zarzdzanie transakcjami ..................................................................................... 453
Klasa JmsGatewaySupport ................................................................................... 453
W przyszoci ....................................................................................................... 455
Planowanie w Springu ............................................................................................... 455
Czasomierze a Quartz .......................................................................................... 456
Czasomierze ....................................................................................................... 457
Framework Quartz ................................................................................................ 459
Wysyanie poczty elektronicznej w Springu ................................................................... 466
Od czego zacz? ................................................................................................ 466
Wielokrotne stosowanie tej samej sesji pocztowej .................................................. 467
Wysyanie wiadomoci przy uyciu COS .................................................................. 468
Meneder poczty elektronicznej oglnego zastosowania .......................................... 468
Zastosowanie jzykw skryptowych ............................................................................ 473
Spjny model ...................................................................................................... 474
Inne jzyki skryptowe ........................................................................................... 479
Podsumowanie ......................................................................................................... 479

Rozdzia 10. System bezpieczestwa Acegi dla Springa ......................................................................481


Sposoby zabezpieczania aplikacji korporacyjnych ......................................................... 481
Typowe wymagania .............................................................................................. 481
System bezpieczestwa Acegi w zarysie ................................................................ 483
Usuga uwierzytelniania i autoryzacji Javy ............................................................... 488
Specyfikacja serwletw ........................................................................................ 491
Podstawy systemu bezpieczestwa Acegi .................................................................... 493
Uwierzytelnianie ................................................................................................... 493
Przechowywanie obiektw Authentication ............................................................... 498
Autoryzacja .......................................................................................................... 500
Bezpieczestwo obiektw dziedziny ....................................................................... 503
Przykad ................................................................................................................... 505
Wprowadzenie do przykadowej aplikacji ................................................................ 505
Implementacja pozbawiona mechanizmw bezpieczestwa ..................................... 507
Rozwizanie wykorzystujce zabezpieczenia ........................................................... 509
Uwierzytelnianie ................................................................................................... 509
Autoryzacja .......................................................................................................... 510
Podsumowanie ......................................................................................................... 514

Rozdzia 11. Spring i EJB ..........................................................................................................................517


Okrelanie, czy stosowanie komponentw EJB jest potrzebne ....................................... 518
Dostp do komponentw EJB ..................................................................................... 519
Typowe rozwizanie .............................................................................................. 520
Rozwizanie z wykorzystaniem Springa .................................................................. 521
Tworzenie komponentw EJB w Springu ...................................................................... 529
Bezstanowe komponenty sesyjne .......................................................................... 529
Stanowe komponenty sesyjne ............................................................................... 532
Komponenty sterowane komunikatami .................................................................. 534
Kilka sw o XDoclet ............................................................................................ 535
Dostp na zasadzie singletonu rozwizanie dobre czy ze? ....................................... 536
ContextSingletonBeanFactoryLocator i SingletonBeanFactoryLocator ........................ 537
Wsplny kontekst jako rodzic kontekstu aplikacji sieciowej .................................. 540
Stosowanie wsplnego kontekstu w komponentach EJB ......................................... 543

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\!!!spis.doc

Spis treci

Zagadnienia zwizane z testowaniem ......................................................................... 543


Implementacja funkcjonalnoci biznesowej w zwyczajnych obiektach Javy ................. 544
Zastosowanie imitacji kontenera EJB ..................................................................... 544
Testy integracyjne w rodowisku serwera aplikacji .................................................. 545
Podsumowanie ......................................................................................................... 546

Rozdzia 12. Framework Web MVC .......................................................................................................547


Prosty przykad ......................................................................................................... 548
Oglna architektura ................................................................................................... 550
Pojcia zwizane z Web MVC ................................................................................ 550
Oglne dziaanie Web MVC wykorzystujce serwlet dyspozytora oraz kontrolery ......... 551
Wymagania dobrego sieciowego frameworku MVC .................................................. 552
Elementy Spring Web MVC ................................................................................... 554
Komponenty infrastruktury ......................................................................................... 556
DispatcherServlet ................................................................................................ 557
WebApplicationContext ......................................................................................... 560
Przepyw sterowania zwizanego z przetwarzaniem da ............................................. 563
Typowy ukad aplikacji Spring MVC ............................................................................. 566
Odwzorowania HandlerMapping .................................................................................. 568
BeanNameUrlHandlerMapping .............................................................................. 568
SimpleUrlHandlerMapping .................................................................................... 569
CommonsPathMapUrlHandlerMapping ................................................................... 571
Wicej ni jedno odwzorowanie HandlerMapping ..................................................... 572
HandlerExecutionChain oraz obiekty przechwytujce .................................................... 573
WebContentInterceptor ........................................................................................ 575
UserRoleAuthorizationInterceptor .......................................................................... 576
Inne obiekty przechwytujce udostpniane przez Spring MVC .................................. 577
Obiekty obsugi oraz ich adaptery ............................................................................... 577
ModelAndView oraz ViewResolver ............................................................................... 577
UrlBasedViewResolver ......................................................................................... 578
BeanNameViewResolver oraz XmlViewResolver ...................................................... 579
ResourceBundleViewResolver ............................................................................... 579
Tworzenie acucha obiektw ViewResolver ........................................................... 580
Zmiana i wybr ustawie lokalnych ............................................................................. 582
Obiekty HandlerExceptionResolver .............................................................................. 584
Kontrolery ................................................................................................................ 587
WebContentGenerator .......................................................................................... 587
AbstractController ................................................................................................ 587
UrlFilenameViewController .................................................................................... 588
ParametrizableViewController ................................................................................ 589
MulitActionController ............................................................................................ 590
Wizanie danych ....................................................................................................... 591
Przydatne moliwoci uywane podczas wizania danych ........................................ 592
Praktyczne przykady zastosowania kontrolerw ........................................................... 593
Przegldanie listy przedstawie przy uyciu kontrolera AbstractController ................. 594
Rezerwacja miejsc ............................................................................................... 596
Kreatory ................................................................................................................... 606
Podstawowa konfiguracja ..................................................................................... 606
Metody szablonowe ............................................................................................. 607
Przepyw sterowania kreatora ................................................................................ 608
Zmiany stron, numeracja oraz inne akcje ............................................................... 609

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\!!!spis.doc

10

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


Rozszerzanie infrastruktury obiektw obsugi ............................................................... 610
Przesyanie plikw na serwer ..................................................................................... 611
Konfiguracja resolvera .......................................................................................... 611
Tworzenie formularza do przesyania plikw na serwer ............................................ 612
Obsuga przesanych danych ................................................................................. 612
Testowanie kontrolerw ............................................................................................. 614
Testowanie bez kontekstu aplikacji ....................................................................... 614
Bardziej szczegowe testowanie przy uyciu obiektw pozornych ............................. 615
Testowanie przy wykorzystaniu penego kontekstu aplikacji ..................................... 616
Inne sposoby testowania aplikacji ......................................................................... 618
Podsumowanie ......................................................................................................... 618

Rozdzia 13. Technologie widokw .........................................................................................................621


Przykad ................................................................................................................... 622
Oglna konfiguracja ............................................................................................. 623
JavaServer Pages ................................................................................................ 623
FreeMarker ......................................................................................................... 624
Generacja dokumentw PDF przy uyciu biblioteki iText ........................................... 624
Czynniki majce wpyw na wybr technologii generacji widokw ..................................... 625
Obiekty widokw i modeli ........................................................................................... 626
Moliwoci klasy AbstractView ................................................................................... 628
Zgaszanie nowych da przy uyciu widokw RedirectView .................................... 629
Uycie prefiksu widoku do generacji przekaza i przekierowa ................................. 631
JavaServer Pages ...................................................................................................... 631
Konfiguracja aplikacji korzystajcej z JSP ............................................................... 632
Tworzenie formularzy przy uyciu znacznikw niestandardowych ............................... 633
Wykorzystanie plikw znacznikw do tworzenia elementw nadajcych si
do wielokrotnego zastosowania .......................................................................... 640
Velocity oraz FreeMarker ............................................................................................ 642
Konfiguracja resolvera widokw ............................................................................ 642
Stosowanie makr uatwiajcych tworzenie formularzy .............................................. 645
Tiles ........................................................................................................................ 648
Widoki bazujce na dokumentach XML i XSLT ............................................................. 652
Widoki generujce arkusze Excela lub inne dokumenty ................................................. 654
Generacja arkusza kalkulacyjnego na podstawie listy przedstawie .......................... 654
Wykorzystanie szablonw jako podstawy do generacji arkuszy kalkulacyjnych ........... 656
Inne widoki generujce dokumenty ........................................................................ 656
Zastosowanie obiektw przechwytujcych HandlerInterceptor w celu rozrniania
wybranego typu odpowiedzi ................................................................................ 657
Implementacja widokw niestandardowych ................................................................. 659
Interfejs View i klasa AbstractView ........................................................................ 659
Implementacja widoku generujcego dane XML na podstawie obiektu danych .......... 660
Czynniki, jakie naley uwzgldnia podczas tworzenia widokw niestandardowych ..... 662
Podsumowanie ......................................................................................................... 662

Rozdzia 14. Integracja z innymi frameworkami sieciowymi .............................................................665


Czynniki wpywajce na wybr uywanego frameworka MVC .......................................... 666
Porwnanie tradycyjnych frameworkw Web MVC .................................................... 666
Integracja z frameworkiem Spring. Pojcia podstawowe ............................................... 682
Integracja z frameworkiem WebWork .......................................................................... 684
Przygotowanie obiektu ObjectFactory ..................................................................... 684

10

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\!!!spis.doc

Spis treci

11

Integracja z frameworkiem Struts ............................................................................... 685


Stosowanie obiektw ActionSupport ...................................................................... 686
Stosowanie klas DelegatingRequestProcessor oraz DelegatingActionProxy ............... 687
Stosowanie bazowej akcji dysponujcej moliwoci automatycznego wizania ......... 691
Integracja z frameworkiem Tapestry ............................................................................ 692
Pobieranie komponentw na potrzeby Tapestry ...................................................... 692
Klasa strony ........................................................................................................ 693
Definicja strony ................................................................................................... 693
Szablon strony ..................................................................................................... 695
Ostatnie informacje o integracji z frameworkiem Tapestry ....................................... 696
Integracja z JavaServer Faces .................................................................................... 697
Podsumowanie ......................................................................................................... 698

Rozdzia 15. Aplikacja przykadowa ......................................................................................................701


Wybr technologii serwera ......................................................................................... 702
Warstwy aplikacji ...................................................................................................... 702
Warstwa trwaoci ..................................................................................................... 704
Model danych ...................................................................................................... 704
Model obiektw dziedziny ..................................................................................... 705
Odwzorowania obiektowo-relacyjne ........................................................................ 707
Implementacja DAO ............................................................................................. 712
Konfiguracja dostpu do danych ........................................................................... 714
Warstwa usug biznesowych ....................................................................................... 715
Usugi ................................................................................................................. 715
Kontekst aplikacji ................................................................................................ 716
Warstwa sieciowa ..................................................................................................... 718
Przepyw sterowania w aplikacji ............................................................................. 718
Konfiguracja aplikacji przy uyciu pliku web.xml ...................................................... 720
Kontrolery sieciowe .............................................................................................. 721
Technologia widokw ........................................................................................... 723
Porwnanie z implementacj przedstawion w ksice J2EE Design and Development ... 725
Prostsza technologia ............................................................................................ 725
Zmiany zwizane z baz danych ............................................................................ 725
Konfiguracja serwera ................................................................................................. 726
MySQL ................................................................................................................ 726
Tomcat ............................................................................................................... 727
Kompilacja aplikacji i jej wdroenie ............................................................................. 727
Utworzenie tabel bazy danych i zapisanie w nich informacji ..................................... 727
Kompilacja aplikacji i wdroenie jej na serwerze Tomcat ......................................... 728
Podsumowanie ......................................................................................................... 728

Rozdzia 16. Wnioski ...............................................................................................................................729


Problemy, jakie rozwizuje Spring ............................................................................... 729
Rozwizania przyjte w Springu .................................................................................. 730
Porady zwizane ze stosowaniem Springa ................................................................... 733
Wybr technologii ................................................................................................ 733
Warstwy aplikacji ................................................................................................. 736
Struktura aplikacji ................................................................................................ 744
Testowanie aplikacji ............................................................................................. 749
Projekty zwizane z frameworkiem Spring .................................................................... 752
System bezpieczestwa Acegi Security .................................................................. 752
Inne projekty ....................................................................................................... 753

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\!!!spis.doc

11

12

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


Spring poza rodowiskiem J2EE ................................................................................. 754
Poszukiwanie informacji dodatkowych ......................................................................... 755
Ksiki i artykuy .................................................................................................. 755
Zasoby dostpne na stronach WWW ..................................................................... 756
Przykadowe aplikacje .......................................................................................... 757
Przyszo ................................................................................................................ 758

A Wymagania dla przykadowej aplikacji .............................................................................................761


Przegld ................................................................................................................... 761
Grupy uytkownikw .................................................................................................. 762
Publiczni uytkownicy internetowi .......................................................................... 762
Kasjerzy .............................................................................................................. 763
Administratorzy .................................................................................................... 763
Zaoenia ................................................................................................................. 764
Ograniczenia zakresu aplikacji .................................................................................... 765
Terminarz prac .......................................................................................................... 765
Interfejs uytkownikw internetowych .......................................................................... 766
Podstawowy schemat dziaania ............................................................................. 766
Obsuga bdw ................................................................................................... 767
Ekrany aplikacji ................................................................................................... 767
Wymagania niefunkcjonalne ....................................................................................... 780
rodowisko sprztowe i programowe .......................................................................... 782

Skorowidz ..............................................................................................................................................785

12

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\!!!spis.doc

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.

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

81

82

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


W rozdziale zajmiemy si nastpujcymi zagadnieniami:
n

odwracaniem kontroli (IoC) i wstrzykiwaniem zalenoci,

podstawowymi technikami konfigurowania obiektw i definiowania relacji


czcych obiekty w ramach kontenera Springa,

sposobem interpretowania zalenoci i rnicami pomidzy jawnym


a automatycznym wprowadzaniem zalenoci,

obsug cyklu ycia obiektw w kontenerze Springa,

abstrakcj technik dostpu do usug i zasobw,

postprocesorami fabryki komponentw i samych komponentw, ktre


odpowiadaj za dostosowywanie zachowania kontenera i komponentw,

technikami programowego korzystania z interfejsw BeanFactory


i ApplicationContext.

W rozdziale 1. opisano koncepcj odwracania kontroli (IoC) i wyjaniono, dlaczego jest


ona tak wana dla procesu wytwarzania oprogramowania. W pierwszej kolejnoci krtko
przypomnimy, co to pojcie rzeczywicie oznacza, by zaraz potem przystpi do analizy
kilku przykadw jego praktycznego stosowania dla kontenera Springa.
Kod oprogramowania rozbija si zwykle na logiczne, wsppracujce ze sob komponenty
lub usugi. W Javie takie komponenty maj przewanie posta egzemplarzy klas, czyli
obiektw. Kady obiekt realizuje swoje zadania z wykorzystaniem lub we wsppracy
z pozostaymi obiektami. Przypumy, e mamy dany obiekt A; mona powiedzie, e pozostae obiekty, z ktrych korzysta obiekt A, s jego zalenociami (ang. dependencies).
Odwracanie kontroli (IoC) jest w wielu sytuacjach podanym wzorcem architekturalnym,
ktry przewiduje, e obiekty s ze sob wizane przez byt zewntrzny (w tym przypadku
kontener), ktry tym samym odpowiada za obsug ich zalenoci (eliminujc konieczno bezporedniego tworzenia egzemplarzy jednych obiektw w drugich).
Przyjrzyjmy si teraz kilku przykadom.
Wikszo przykadw prezentowanych w tym rozdziale (nawet tych, ktre nie s prezentowane w formie kompletnych klas czy interfejsw) jest dostpna take w postaci
gotowej do kompilacji, z ktr moesz swobodnie eksperymentowa (patrz ftp://ftp.
helion.pl/przyklady/sprifr.zip).
Przypumy, e dysponujemy usug obsugujc historyczne dane pogodowe, ktr zakodowano w tradycyjny sposb (bez korzystania z kontenera IoC):
public class WeatherService {
WeatherDao weatherDao = new StaticDataWeatherDaoImpl();

82

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

83

public Double getHistoricalHigh(Date date) {


WeatherData wd = weatherDao.find(date);
if (wd != null)
return new Double(wd.getHigh());
return null;
}

public interface WeatherDao {

WeatherData find(Date date);


WeatherData save(Date date);
WeatherData update(Date date);

public class StaticDataWeatherDaoImpl implements WeatherDao {


public WeatherData find(Date date) {
WeatherData wd = new WeatherData();
wd.setDate((Date) date.clone());
...
return wd;
}
public WeatherData save(Date date) {
...
}

public WeatherData update(Date date) {


...
}

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

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

83

84

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


DAO (okrelonego typu) jest przez t usug tworzony bezporednio i wanie usuga pogodowa steruje jego cyklem ycia; oznacza to, e wspomniana usuga jest obarczona zalenociami zarwno od interfejsu DAO, jak i konkretnej klasy implementujcej ten interfejs.
Co wicej, przykadowa aplikacja testowa reprezentuje klienta tej usugi, ktry bezporednio tworzy egzemplarz konkretnego typu usugi pogodowej, zamiast korzysta z porednictwa waciwego interfejsu. W rzeczywistej aplikacji bardzo prawdopodobne byoby wystpowanie innych niejawnych zalenoci (np. od konkretnego frameworku utrwalania
danych), a prezentowane do tej pory podejcie wymagaoby kodowania tych zalenoci na
stae w kodzie rdowym programu.
Spjrzmy teraz na prosty przykad tego, jak kontener Springa moe obsugiwa mechanizm
odwracania kontroli. W pierwszej kolejnoci przebudujemy nasz usug pogodow, aby
prezentowaa waciwy podzia na interfejs i implementacj oraz umoliwiaa definiowanie
(konfigurowanie) dla tej implementacji konkretnego egzemplarza obiektu DAO w formie
waciwoci komponentu JavaBean:
public interface WeatherService {
Double getHistoricalHigh(Date date);
}
public class WeatherServiceImpl implements WeatherService {
private WeatherDao weatherDao;
public void setWeatherDao(WeatherDao weatherDao) {
this.weatherDao = weatherDao;
}

public Double getHistoricalHigh(Date date) {


WeatherData wd = weatherDao.find(date);
if (wd != null)
return new Double(wd.getHigh());
return null;
}

// ta sama klasa co w poprzednim przykadzie


public class StaticDataWeatherDaoImpl implements WeatherDao {
...
}

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

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

85

</property<
</bean<
<bean id="weatherDao" class="ch02.sample2.StaticDataWeatherDaoImpl"<
</bean<
</beans<

Obiekt weatherService konfigurujemy za pomoc elementu bean, w ktrym okrelamy, e


jego waciwo, weatherDao, powinna by ustawiona na egzemplarz komponentu weatherDao
(ktry take definiujemy jako element bean). Pozostaje nam ju tylko zmodyfikowanie klasy
testowej, aby tworzya odpowiedni kontener i uzyskiwaa dostp do znajdujcej si w tym
kontenerze usugi pogodowej:
public class WeatherServiceTest extends TestCase {
public void testSample2() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"ch02/sample2/applicationContext.xml");
WeatherService ws = (WeatherService)ctx.getBean("weatherService");
Double high = ws.getHistoricalHigh(new GregorianCalendar(2004, 0, 1).getTime());
// w tym miejscu powiniene umieci dodatkowy kod sprawdzajcy zwracan warto
}

Wszystkie analizowane klasy zostay ju zakodowane i wdroone zgodnie z zaleceniami


IoC. Usuga pogodowa nie ma i nie potrzebuje adnej wiedzy o szczegach implementacji
wykorzystywanego obiektu DAO, poniewa zaleno pomidzy tymi skadnikami aplikacji
bazuje wycznie na interfejsie WeatherDao. Co wicej, podzia oryginalnej klasy WeatherService na interfejs WeatherService i implementujc go klas WeatherServiceImpl chroni klientw usugi pogodowej przed takimi szczegami implementacyjnymi jak sposb lokalizowania przez t usug odpowiedniego obiektu DAO (w tym konkretnym przypadku wykorzystano metod ustawiajc znan z komponentw JavaBeans). Takie rozwizanie powoduje,
e teraz implementacja usugi pogodowej moe by zmieniana w sposb przezroczysty.
Okazuje si, e na tym etapie moemy wymienia implementacje interfejsu WeatherDao
i (lub) interfejsu WeatherService, i e tego rodzaju zmiany bd wymagay wycznie odpowiedniego dostosowania zapisw pliku konfiguracyjnego (bez najmniejszego wpywu na
funkcjonowanie klientw zmienianych komponentw). Przedstawiony przykad dobrze ilustruje zastosowanie interfejsw w sytuacji, gdy kod jednej z warstw wykorzystuje kod innej
warstwy (wspominano o tym w rozdziale 1.).

Rne formy wstrzykiwania zalenoci


Termin wstrzykiwanie zalenoci (ang. Dependency Injection) opisuje proces dostarczania
komponentowi niezbdnych zalenoci z wykorzystaniem techniki IoC mona wic powiedzie, e zalenoci s w istocie wstrzykiwane do komponentw. Wersja wstrzykiwania
zalenoci, ktr mielimy okazj analizowa w poprzednim przykadzie, jest nazywana
wstrzykiwaniem przez metody ustawiajce (ang. Setter Injection), poniewa do wprowadzania (wstrzykiwania) zalenoci do waciwych obiektw wykorzystuje si znane z komponentw JavaBeans metody ustawiajce. Wicej informacji na temat komponentw JavaBeans oraz specyfikacj tej technologii znajdziesz na stronie internetowej http://java.sun.
com/products/javabeans.

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

85

86

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


Przeanalizujmy teraz nieco inny wariant wstrzykiwania zalenoci wstrzykiwanie przez
konstruktor (ang. Constructor Injection), gdzie zalenoci s dostarczane do obiektu za
porednictwem jego wasnego konstruktora:
public interface WeatherService {
Double getHistoricalHigh(Date date);
}
public class WeatherServiceImpl implements WeatherService {
private final WeatherDao weatherDao;
public WeatherServiceImpl(WeatherDao weatherDao) {
this.weatherDao = weatherDao;
}

public Double getHistoricalHigh(Date date) {


WeatherData wd = weatherDao.find(date);
if (wd != null)
return new Double(wd.getHigh());
return null;
}

// niezmieniony interfejs WeatherDao


public interface WeatherDao {
...
}
// niezmieniona klasa StaticDataWeatherDaoImpl
public class StaticDataWeatherDaoImpl implements WeatherDao {
...
}

Klasa WeatherServiceImpl zawiera teraz konstruktor, ktry pobiera w formie argumentu


egzemplarz interfejsu WeatherDao (zamiast jak w poprzednim przykadzie odpowiedniej metody ustawiajcej, ktra take pobieraa na wejciu egzemplarz tego interfejsu).
Oczywicie take konfiguracja kontekstu aplikacji wymaga odpowiedniej modyfikacji.
Okazuje si jednak, e zmiany w aden sposb nie dotycz klasy testowej, ktra nie wymaga
adnych dodatkowych czynnoci:
<beans<
<bean id="weatherService" class="ch02.sample3.WeatherServiceImpl"<
<constructor-arg<
<ref local="weatherDao"/<
</constructor-arg<
</bean<
<bean id="weatherDao" class="ch02.sample3.StaticDataWeatherDaoImpl"<
</bean<
</beans<
// niezmieniona klasa WeatherServiceTest
public class WeatherServiceTest extends TestCase {
...
}

86

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

87

Wstrzykiwanie metod jest ostatni form wstrzykiwania zalenoci, ktr si zajmiemy


(jest stosowana zdecydowanie rzadziej od dwch poprzednich technik). Wstrzykiwanie zalenoci w tej formie przenosi na kontener odpowiedzialno za implementowanie metod
w czasie wykonywania programu. Przykadowo, obiekt moe definiowa chronion metod
abstrakcyjn, a kontener moe t metod implementowa w czasie wykonywania programu
w taki sposb, aby zwracaa obiekt zlokalizowany podczas przeszukiwania rodowiska wykonywania aplikacji. Celem wstrzykiwania metod jest oczywicie wyeliminowanie zalenoci od interfejsw API kontenera i tym samym ograniczanie niepodanych zwizkw.
Jednym z podstawowych i jednoczenie najlepszych zastosowa techniki wstrzykiwania
metod jest obsuga przypadkw, w ktrych bezstanowy obiekt, singleton, musi wsppracowa z niesingletonem, z obiektem stanowym lub takim, ktry nie zapewnia bezpieczestwa przetwarzania wielowtkowego. Przypomnij sobie nasz usug pogodow, w ktrej
potrzebujemy tylko jednego egzemplarza, poniewa nasza implementacja jest bezstanowa
i jako taka moe by wdraana za pomoc domylnego kontenera Springa, ktry traktuje j
jak singleton (tworzy tylko jeden egzemplarz, ktry mona przechowywa w pamici podrcznej i wykorzystywa wielokrotnie). Warto si jednak zastanowi, co by byo, gdyby
usuga pogodowa musiaa korzysta z klasy StatefulWeatherDao, implementacji interfejsu
WeatherDao niezapewniajcej bezpieczestwa wtkw. W kadym wywoaniu metody
WeatherService.getHistoricalHigh() usuga pogodowa musiaaby wykorzystywa wiey
egzemplarz obiektu DAO (lub przynajmniej musiaaby si upewnia, e w danej chwili aden inny egzemplarz samej usugi nie wykorzystuje tego samego obiektu DAO). Jak si za
chwil przekonasz, mona w prosty sposb zasygnalizowa kontenerowi konieczno
traktowania DAO jak obiektu, ktry nie jest singletonem wwczas kade danie dotyczce tego obiektu spowoduje zwrcenie nowego egzemplarza. Problem w tym, e pojedynczy egzemplarz usugi pogodowej jest przedmiotem wstrzykiwania zalenoci tylko raz.
Jednym z rozwiza jest oczywicie umieszczenie w kodzie tej usugi odwoa do interfejsu
API kontenera Springa i w razie potrzeby danie nowego obiektu DAO. Takie podejcie
ma jednak jedn zasadnicz wad: wie nasz usug ze Springiem, co jest sprzeczne
z deniem do jak najwikszej izolacji obu struktur. Zamiast tego moemy zastosowa oferowany przez Springa mechanizm wstrzykiwania metody wyszukujcej (ang. Lookup
Method Injection), gdzie usuga pogodowa bdzie miaa dostp do odpowiedniego obiektu
DAO za porednictwem metody JavaBean getWeatherDao(), ktra w zalenoci od potrzeb moe by albo konkretn implementacj albo metod abstrakcyjn. Nastpnie, ju
w definicji fabryki, nakazujemy kontenerowi przykrycie tej metody i zapewnienie implementacji zwracajcej nowy egzemplarz DAO w formie innego komponentu:
public abstract class WeatherServiceImpl implements WeatherService {
protected abstract WeatherDao getWeatherDao();

public Double getHistoricalHigh(Date date) {


WeatherData wd = getWeatherDao().find(date);
if (wd != null)
return new Double(wd.getHigh());
return null;
}

<beans<
<bean id="weatherService" class="ch02.sample4.WeatherServiceImpl"<

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

87

88

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


<lookup-method name="getWeatherDao" bean="weatherDao"/<
</bean<
<bean id="weatherDao" singleton="false"
class="ch02.sample4.StatefulDataWeatherDaoImpl"<
</bean<
</beans<

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

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

89

Wybr pomidzy wstrzykiwaniem


przez metody ustawiajce a wstrzykiwaniem przez konstruktory
Podczas korzystania z istniejcych klas moe si zdarzy, e nie bdziesz nawet mia wyboru pomidzy uyciem techniki wstrzykiwania przez metody ustawiajce a zastosowaniem
wstrzykiwania przez konstruktor. Jeli dana klasa zawiera wycznie wieloargumentowy
konstruktor i adnych waciwoci komponentu JavaBean lub jednoargumentowy konstruktor i proste waciwoci JavaBean, wybr metody wstrzykiwania nie zaley od Ciebie
dokonano go ju wczeniej. Co wicej, niektre spord istniejcych klas mog wymusza stosowanie kombinacji obu form wstrzykiwania zalenoci, gdzie oprcz wieloargumentowego konstruktora bdziesz zobligowany do ustawienia kilku opcjonalnych waciwoci JavaBean.
Jeli masz wybr odnonie wersji wstrzykiwania zalenoci, ktrej chcesz uy lub dla ktrej
chcesz zaprojektowa architektur swojej aplikacji, przed podjciem ostatecznej decyzji
powiniene wzi pod uwag kilka czynnikw:
n

Stosowanie waciwoci JavaBean generalnie uatwia obsug domylnych lub


opcjonalnych wartoci w sytuacji, gdy nie wszystkie wartoci faktycznie s wymagane.
W przypadku wstrzykiwania przez konstruktor takie podejcie musiaoby prowadzi
do stworzenia wielu wariantw konstruktora, gdzie jeden konstruktor wywoywaby
w swoim ciele inny. Wiele wersji konstruktora i dugie listy argumentw mog by
zbyt rozwleke i utrudnia konserwacj kodu.

W przeciwiestwie do konstruktorw waciwoci JavaBean (jeli nie s prywatne)


s automatycznie dziedziczone przez podklasy. Ograniczenie zwizane z dziedziczeniem
konstruktorw czsto zmusza programistw do tworzenia w kodzie podklas
szablonowych konstruktorw, ktrych jedynym zadaniem jest wywoywanie
odpowiednich konstruktorw nadklasy. Warto jednak pamita, e wikszo
rodowisk IDE oferuje obecnie rozmaite mechanizmy uzupeniania kodu, ktre
czyni proces tworzenia konstruktorw lub waciwoci JavaBean niezwykle atwym.

Waciwoci JavaBean s zdecydowanie atwiejsze w interpretacji (nawet bez


stosowania dodatkowych komentarzy dokumentujcych) na poziomie kodu
rdowego ni argumenty konstruktora. Waciwoci JavaBean wymagaj te
mniejszego wysiku podczas dodawania komentarzy JavaDoc, poniewa
(w przeciwiestwie do konstruktorw) nie powtarzaj si w kodzie.

W czasie dziaania, waciwoci JavaBean mog by dopasowywane wedug nazw,


ktre s widoczne z poziomu mechanizmu refleksji Javy. Z drugiej strony,
w skompilowanym pliku klasy uyte w kodzie rdowym nazwy argumentw
konstruktora nie s zachowywane, zatem automatyczne dopasowywanie wedug
nazw jest niemoliwe.

Waciwoci JavaBean oferuj moliwo zwracania (i ustawiania) biecego stanu,


jeli tylko zdefiniowano odpowiedni metod zwracajc (i ustawiajc). Takie
rozwizanie jest w wielu sytuacjach niezwykle przydatne, np. kiedy naley zapisa
biecy stan w innymi miejscu.

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

89

90

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


n

Interfejs PropertyPritor dla waciwoci JavaBean umoliwia wykonywanie


automatycznej konwersji typw tam, gdzie jest to konieczne. Wanie to wygodne
rozwizanie jest wykorzystywane i obsugiwane przez Springa.

Waciwoci JavaBean mog by zmienne, poniewa odpowiednie metody ustawiajce


mona wywoywa wiele razy. Oznacza to, e jeli wymaga tego realizowany
przypadek testowy, mona w prosty sposb modyfikowa istniejce zalenoci.
Inaczej jest w przypadku zalenoci przekazywanych za porednictwem konstruktorw,
ktre jeli nie s dodatkowo udostpniane w formie waciwoci pozostaj
niezmienne. Z drugiej strony, jeli jednym z wymaga jest bezwzgldna niezmienno
zalenoci, wanie technika wstrzykiwania przez konstruktor umoliwia zadeklarowanie
pola ustawianego w ciele konstruktora ze sowem kluczowym final (metoda
ustawiajca w najlepszym razie moe odpowiedzie wyjtkiem na prb drugiego
lub kolejnego wywoania; nie ma te moliwoci zadeklarowania pola ustawianego
w takiej metodzie ze sowem kluczowym final, ktre zabezpieczyoby to pole
przed ewentualnymi modyfikacjami przez pozostay kod danej klasy).

Argumenty konstruktora daj programicie pewno, e poprawny obiekt zostanie


skonstruowany, poniewa zadeklarowanie wszystkich wymaganych wartoci
wymusi ich przekazanie, a sama klasa w procesie inicjalizacji moe je wykorzystywa
w wymaganej kolejnoci w procesie inicjalizacji. W przypadku waciwoci
JavaBean nie mona wykluczy sytuacji, w ktrej cz waciwoci nie zostaa
ustawiona przed uyciem danego obiektu, ktry tym samym znajdowa si
w niewaciwym stanie. Co wicej, jeli uyjesz waciwoci JavaBean, nie bdziesz
mg w aden sposb wymusi kolejnoci wywoa metod ustawiajcych, co moe
wymaga dodatkowych zabiegw inicjalizujcych ju po ustawieniu waciwoci
(za pomoc metody init()). Taka dodatkowa metoda moe te sprawdza, czy
wszystkie waciwoci zostay ustawione. Spring oferuje mechanizmy automatycznego
wywoywania dowolnej zadeklarowanej metody inicjalizujcej bezporednio
po ustawieniu wszystkich waciwoci; alternatywnym rozwizaniem jest
zaimplementowanie interfejsu InitializingBean, ktry deklaruje automatycznie
wywoywan metod afterPropertiesSet().

Stosowanie kilku konstruktorw moe by bardziej zwizym rozwizaniem


ni korzystanie z wielu waciwoci JavaBean wraz z odpowiednimi metodami
ustawiajcymi i zwracajcymi. Wikszo rodowisk IDE oferuje jednak funkcje
uzupeniania kodu, ktre bardzo uatwiaj i skracaj proces tworzenia zarwno
konstruktorw, jak i waciwoci JavaBean.

Oglnie, zesp Springa w wikszoci praktycznych zastosowa preferuje stosowanie techniki


wstrzykiwania przez metody ustawiajce zamiast wstrzykiwania przez konstruktory, cho
tego rodzaju decyzje powinny by dobrze przemylane i w adnym razie nie naley uprawia doktrynerstwa. Wymienione powyej aspekty obejmuj wikszo czynnikw, ktre
naley bra pod uwag w kadej z sytuacji. Przyjmuje si, e wstrzykiwanie przez konstruktory lepiej si sprawdza w przypadku prostszych scenariuszy inicjalizacji, gdzie konstruktor otrzymuje na wejciu zaledwie kilka argumentw, ktre dodatkowo powinny reprezentowa zoone, a wic atwiejsze do dopasowania, i unikatowe typy. Wraz ze wzrostem
zoonoci caej konfiguracji ronie przewaga techniki wstrzykiwania przez metody
ustawiajce (zarwno w zakresie moliwoci konserwacji, jak i nakadw pracy samego
programisty). Warto pamita, e take inne popularne kontenery IoC obsuguj zarwno

90

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

91

wstrzykiwanie przez konstruktory, jak i wstrzykiwanie przez metody ustawiajce, zatem


obawa przed nadmiernym zwizaniem aplikacji z mechanizmami Springa nie powinna by
uwzgldniana podczas dokonywania tego wyboru.
Niezalenie od wybranej formy wstrzykiwania zalenoci jest oczywiste, e naley ten mechanizm stosowa w taki sposb, aby odpowiednie konstrukcje byy wprowadzane wycznie do klasy implementacji oraz waciwej konfiguracji tej klasy. Pozostay kod aplikacji
powinien wsppracowa z pozostaymi moduami (komponentami) za porednictwem interfejsw i w aden sposb nie powinien by uzaleniony od problemw konfiguracyjnych.

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

podstawowy interfejs wykorzystywany do uzyskiwania dostpu do


wszystkich fabryk komponentw. Przykadowo wywoanie metody getBean(String
name) umoliwia uzyskanie komponentu z kontenera na podstawie nazwy. Inny
wariant tej metody, getBean(String name, Class requirerType), dodatkowo daje

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

91

92

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


programicie moliwo okrelenia wymaganej klasy zwracanego komponentu
i generuje wyjtek, jeli taki komponent nie istnieje. Inne metody umoliwiaj nam
odpytywanie fabryki komponentw w zakresie istnienia poszczeglnych komponentw
(wedug nazw), odnajdywanie typw komponentw (take wedug nazw) oraz
sprawdzanie, czy w danej fabryce istniej jakie aliasy danego komponentu (czy
dany komponent wystpuje w fabryce pod wieloma nazwami). I wreszcie mona
okreli, czy dany komponent skonfigurowano jako singleton (czy pierwszy
utworzony egzemplarz komponentu bdzie wykorzystywany wielokrotnie dla
wszystkich kolejnych da czy fabryka za kadym razem bdzie tworzya nowy
egzemplarz).
n HierarchicalBeanFactory

wikszo fabryk komponentw moe by tworzona


jako cz wikszej hierarchii wwczas danie od fabryki dostpu do komponentu,
ktry w tej konkretnej fabryce nie istnieje, spowoduje przekazanie dania do jego
fabryki nadrzdnej (przodka), ktra moe z kolei zada odpowiedniego komponentu
od swojej fabryki nadrzdnej itd. Z perspektywy aplikacji klienta caa hierarchia
powyej biecej fabryki (wcznie z t fabryk) moe by traktowana jak jedna,
scalona fabryka. Jedn z zalet takiej hierarchicznej struktury jest moliwo jej
dopasowania do rzeczywistych warstw architekturalnych lub moduw aplikacji.
O ile uzyskiwanie komponentu z fabryki bdcej czci hierarchii odbywa si
w sposb cakowicie przezroczysty, interfejs HierarchicalBeanFactory jest
niezbdny, jeli chcemy mie moliwo dostpu do komponentw skadowanych
w jej fabryce nadrzdnej.

n ListableBeanFactory

metody tego podinterfejsu interfejsu BeanFactory


umoliwiaj generowanie rozmaitych list komponentw dostpnych w biecej
fabryce, wcznie z list nazw komponentw, nazwami wszystkich komponentw
okrelonego typu oraz liczb komponentw w danej fabryce. Kilka metod tego
interfejsu umoliwia dodatkowo tworzenie egzemplarza Map zawierajcego
wszystkie komponenty okrelonego typu. Warto pamita, e o ile metody interfejsu
BeanFactory automatycznie s udostpniane na wszystkich poziomach hierarchii
fabryk komponentw, metody interfejsu ListableBeanFactory s stosowane tylko
dla jednej, biecej fabryki. Klasa pomocnicza BeanFactoryUtils oferuje niemal
identyczne metody jak interfejs ListableBeanFactory, tyle e w przeciwiestwie
do metod tego interfejsu uwzgldniaj w generowanych wynikach ca hierarchi
fabryk komponentw. W wielu przypadkach stosowanie metod klasy BeanFactoryUtils
jest lepszym rozwizaniem ni korzystanie z interfejsu ListableBeanFactory.

n AutowireCapableBeanFactory

interfejs AutowireCapableBeanFactory umoliwia


(za porednictwem metod autowireBeanProperties() oraz applyBeanPropertyValues())
konfigurowanie istniejcego, zewntrznego obiektu i dostarczanie zalenoci
z poziomu fabryki komponentw. Oznacza to, e wspomniane metody pozwalaj
pomin normalny krok tworzenia obiektu bdcy czci uzyskiwania komponentu
za porednictwem metody BeanFactory.getBean(). Podczas pracy z zewntrznym
kodem, ktry wymaga tworzenia egzemplarzy obiektw jako takich, tworzenie
komponentw za pomoc odpowiednich mechanizmw Springa nie zawsze jest
moliwe, co nie oznacza, e naley rezygnowa z oferowanych przez ten framework
cennych rozwiza w zakresie wstrzykiwania zalenoci. Inna metoda, autowire(),
umoliwia okrelanie na potrzeby fabryki komponentw nazwy klasy, wykorzystanie
tej fabryki do utworzenia egzemplarza tej klasy, uycie refleksji do wykrycia
wszystkich zalenoci tej klasy i wstrzyknicia tych zalenoci do danego

92

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

93

komponentu (w efekcie powiniene otrzyma w peni skonfigurowany obiekt).


Warto pamita, e fabryka nie bdzie zawieraa i zarzdzaa obiektami
konfigurowanymi za pomoc tych metod (inaczej ni w przypadku tworzonych
przez siebie egzemplarzy singletonw), cho moemy sami doda do tej fabryki
nasze egzemplarze jako singletony.
n ConfigurableBeanFactory

ten interfejs wprowadza do podstawowej fabryki


komponentw dodatkowe opcje konfiguracyjne, ktre mog by stosowane
w fazie inicjalizacji.

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.

Oglnie wszystkie zadania, ktre mona realizowa za pomoc fabryki komponentw,


mona te wykonywa z wykorzystaniem kontekstu aplikacji. Po co wic wprowadzono takie
rozrnienie? Przede wszystkim po to, aby podkreli zwikszon funkcjonalno i nieco
inny sposb uywania kontekstu aplikacji:
n

Oglny styl pracy z frameworkiem pewne operacje na komponentach


w kontenerze lub na samym kontenerze, ktre w fabryce komponentw musz
by obsugiwane programowo, w kontekcie aplikacji mog by realizowane
deklaratywnie. Chodzi midzy innymi o rozpoznawanie i stosowanie specjalnych
postprocesorw dla komponentw oraz postprocesorw dla fabryki komponentw.
Co wicej, istnieje wiele mechanizmw Springa, ktre uatwiaj automatyczne
wczytywanie kontekstw aplikacji przykadowo, w warstwie MVC aplikacji
internetowych wikszo fabryk komponentw bdzie tworzona przez kod
uytkownika, natomiast konteksty aplikacji bd wykorzystywane najczciej za
pomoc technik deklaratywnych i tworzone przez kod Springa. W obu przypadkach
znaczna cz kodu uytkownika bdzie oczywicie zarzdzana przez kontener,
zatem nie bdzie dysponowaa adn wiedz o samym kontenerze.

Obsuga interfejsu MessageSource kontekst aplikacji implementuje interfejs


MessageSource, ktrego zadaniem jest uzyskiwanie zlokalizowanych komunikatw
i ktrego implementacja moe by w prosty sposb wczana do aplikacji.

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

93

94

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie

Rysunek 2.1.

Obsuga zdarze aplikacji i frameworka kontekst aplikacji oferuje moliwo


wywoywania zdarze frameworka lub aplikacji, ktre s nastpnie przechwytywane
i obsugiwane przez zarejestrowane obiekty nasuchujce.

Obsuga interfejsu ResourceLoader interfejs ResourceLoarer Springa jest


elastyczn i uniwersaln abstrakcj obsugujc niskopoziomowe zasoby. Sam
kontekst aplikacji jest implementacj tego interfejsu i tym samym zapewnia
aplikacji dostp do egzemplarzy Resource waciwych dla danego wdroenia.

By moe zastanawiasz si, kiedy lepszym rozwizaniem jest tworzenie i korzystanie


z fabryki komponentw, a kiedy lepiej uy kontekstu aplikacji. Niemal we wszystkich
przypadkach warto rozway uycie kontekstu aplikacji, ktry bez adnych dodatkowych
kosztw poszerza zakres funkcjonalnoci. Prawdopodobnie jedynym wyjtkiem od tej
reguy s aplikacje bazujce na apletach, gdzie kady zajmowany (lub przesyany) bajt
pamici moe mie ogromne znaczenie fabryka komponentw pozwala na pewne
oszczdnoci w tym zakresie, poniewa umoliwia korzystanie z pakietu bibliotek
Springa, ktre zawieraj wycznie funkcjonalno fabryki (bez rozbudowanej funkcjonalnoci kontekstu aplikacji). W tym i innych rozdziaach powiconych funkcjonalnoci fabryki komponentw moesz bezpiecznie zakada, e wszystkie analizowane
elementy funkcjonalnoci s wsplne zarwno dla fabryki komponentw, jak i dla kontekstu aplikacji.

94

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

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;

Mona te wskaza konkretn lokalizacj w systemie plikw:


ApplicationContext appContext =
new FileSystemXmlApplicationContext("/some/file/path/applicationContext.xml");

Istnieje te moliwo czenia dwch lub wikszej liczby fragmentw prezentowanych ju


dokumentw XML. Takie rozwizanie umoliwia nam lokalizowanie definicji komponentw w ramach logicznych moduw, do ktrych nale, i jednoczenie tworzenie jednego
kontekstu na bazie poczonych definicji. Przykad prezentowany w nastpnym rozdziale
pokae, e opisane podejcie moe by bardzo uyteczne take podczas testw. Poniej
przedstawiono jeden z wczeniejszych przykadw konfiguracji, tyle e tym razem zoony
z dwch fragmentw kodu XML:
applicationContext-dao.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="weatherDao" class="ch02.sample2.StaticDataWeatherDaoImpl"<
</bean<
</beans<

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

95

96

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


applicationContext-services.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 bean="weatherDao"/<
</property<
</bean<
</beans<

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

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

97

Rwnie dobrze moglibymy uy egzemplarza InputStream:


InputStream is = new FileInputStream("/some/file/path/beans.xml");
XmlBeanFactory factory = new XmlBeanFactory(is);

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);

Stosujc klas GenericApplicationContext dla kontekstu aplikacji, moemy w podobny


sposb oddzieli kod tworzcy ten kontekst od kodu przetwarzajcego definicje komponentw. Wiele aplikacji Springa w ogle nie tworzy kontenera programowo, poniewa bazuje
na odpowiednim kodzie tego frameworka (ktry wykonuje odpowiednie dziaania w ich
imieniu). Przykadowo, moemy deklaratywnie skonfigurowa mechanizm ContextLoarer
Springa w taki sposb, aby automatycznie wczytywa kontekst aplikacji w momencie
uruchamiania aplikacji internetowej. Odpowiednie techniki konfiguracji omwimy w nastpnym rozdziale.

Korzystanie komponentw uzyskiwanych z fabryki


Kiedy ju fabryka komponentw lub kontekst aplikacji zostan wczytane, uzyskanie dostpu
do komponentw sprowadza si do wywoania metody getBean() interfejsu BeanFactory:
WeatherService ws = (WeatherService)ctx.getBean("weatherService");

lub jednej z metod ktrego z bardziej zaawansowanych interfejsw:


Map allWeatherServices = ctx.getBeansOfType(WeatherService.class);

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.

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

97

98

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie

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).

Konfiguracja komponentw w formacie XML


Mielimy ju okazj przejrze przykadowe pliki z definicjami fabryk komponentw w formacie
XML, jednak do tej pory nie poddalimy zawartych tam zapisw szczegowej analizie.
W najwikszym uproszczeniu definicja fabryki komponentw skada si z elementu beans
(na najwyszym poziomie) oraz jednego lub wielu elementw bean:
<?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"/<
</property<
</bean<
<bean id="weatherDao" class="ch02.sample2.StaticDataWeatherDaoImpl"<
</bean<
</beans<

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

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

99

Podstawowa definicja komponentu


Definicja pojedynczego komponentu zawiera wszystkie informacje, ktrych kontener potrzebuje do jego utworzenia, w tym troch szczegowych danych o cyklu ycia komponentu oraz jego zalenociach. Przyjrzyjmy si dwm pierwszym skadnikom elementu bean.

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<

Poniewa trzeci definiowany komponent wymaga identyfikatora rozpoczynajcego si od


znaku ukonika (/), uycie atrybutu ir jest niemoliwe musimy uy atrybutu name. Zauwa, e czwarty komponent zawiera a trzy identyfikatory, wszystkie rwnie poprawne.
By moe zastanawiasz si, po co w ogle miaby definiowa wicej ni jeden identyfikator
dla komponentu. Dobr praktyk jest takie dzielenie konfiguracji wedug komponentw lub

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

99

100

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


moduw, aby dla kadego moduu istnia fragment pliku XML zawierajcy komponenty
powizane z tym moduem (wraz z ich zalenociami). Nazwy tych zalenoci mog (jak
w przedstawionym przykadzie) by definiowane z prefiksem waciwym dla danego komponentu (w tym przypadku rataSource). Kiedy fabryka komponentw lub kontekst aplikacji jest ostatecznie budowany z wielu przygotowanych wczeniej fragmentw (lub kiedy
tworzona jest hierarchia kontekstw patrz dalsza cz tego rozdziau), kady z tych
komponentw bdzie si odwoywa do tego samego, fizycznego bytu. Takie rozwizanie
naley traktowa jak techniczn prb rozwizania problemu izolacji komponentw.

Mechanizm tworzenia komponentw


Moe te zaistnie konieczno wskazania kontenerowi sposobu, w jaki ten powinien tworzy lub uzyskiwa egzemplarze komponentu, kiedy bdzie tego potrzebowa. Najczciej
stosowanym mechanizmem jest tworzenie komponentu za porednictwem jego konstruktora.
Do okrelania nazwy klasy komponentu suy atrybut class. Za kadym razem, gdy kontener
potrzebuje nowego egzemplarza komponentu, wewntrznie wykonuje odpowiednik znanego
z jzyka Java operatora new. Wszystkie prezentowane do tej pory przykady wykorzystyway wanie ten mechanizm.
Innym mechanizmem tworzenia komponentw jest sygnalizowanie kontenerowi koniecznoci uycia statycznej metody fabrykujcej (ang. factory method), ktrej jedynym zadaniem jest
zwracanie nowego egzemplarza komponentu. Istniejcy kod, nad ktrym nie masz kontroli,
bdzie Ci czasami zmusza do korzystania z takiej statycznej metody fabrykujcej. Nazw
klasy zawierajcej t metod mona okreli za porednictwem atrybutu class, natomiast
nazw samej metody farykujcej naley zdefiniowa w atrybucie factory-methor:
...
<bean id="testBeanObtainedViaStaticFactory"
class="ch02.sample4.StaticFactory" factory-method="getTestBeanInstance"/<
...
public class StaticFactory {
public static TestBean getTestBeanInstance() {
return new TestBean();
}
}

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

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

101

public class NonStaticFactory {


public TestBean getTestBeanInstance() {
return new TestBean();
}
}

Kiedy bdzie potrzebny nowy egzemplarz komponentu testBeanObtainerViaNonStaticFactory,


kontener w pierwszej kolejnoci utworzy egzemplarz fabryki nonStaticFactory i wywoa
udostpnian przez t fabryk metod getTestBeanInstance(). Zauwa, e w tym przypadku
w ogle nie okrelilimy wartoci atrybutu class.
Kiedy ju uda si uzyska nowy egzemplarz obiektu, kontener traktuje go dokadnie tak
samo jak wszystkie pozostae egzemplarze, niezalenie od tego, czy zosta utworzony za
porednictwem konstruktora, statycznej metody fabrykujcej czy metody fabrykujcej innego egzemplarza. Oznacza to, e kady z tych egzemplarzy moe by przedmiotem
wstrzykiwania zalenoci przez metody ustawiajce i podlega normalnemu cyklowi ycia
(w tym odpowiednim wywoaniom zwrotnym).

Komponenty singletonowe kontra komponenty niesingletonowe (prototypowe)


Wanym aspektem cyklu ycia komponentu jest to, czy kontener traktuje go jak singleton
czy jak zwyk klas z wieloma egzemplarzami. Domylne komponenty singletonowe s
tworzone przez kontener tylko raz. Kontener nastpnie przechowuje i wykorzystuje ten sam
egzemplarz komponentu za kadym razem, gdy nastpuje odwoanie do danego komponentu. Takie rozwizanie moe oznacza znaczne oszczdnoci zasobw (w szczeglnoci
pamici, ale take obcienia procesora) w porwnaniu z tworzeniem nowego egzemplarza
komponentu w odpowiedzi na kade kolejne danie. Komponenty singletonowe s wic
najlepszym rozwizaniem zawsze wtedy, gdy tylko implementacja waciwych klas dopuszcza tak moliwo; czyli wtedy, gdy komponent jest bezstanowy lub gdy jego stan
jest ustawiany tylko raz, w czasie inicjalizacji, i tym samym zapewnia bezpieczestwo wtkw (moe by wykorzystywany jednoczenie przez wicej ni jeden wtek).
Komponenty singletonowe s rozwizaniem domylnym, poniewa zdecydowana wikszo praktycznych usug, kontrolerw i zasobw konfigurowanych w ramach kontenera
i tak jest implementowana w formie klas gwarantujcych bezpieczn prac w rodowisku
wielowtkowym, zatem nie modyfikuj swojego stanu po wykonaniu fazy inicjalizacji.
Niesingletonowe, prototypowe komponenty, jak sama nazwa wskazuje, powinny by definiowane z atrybutem singleton rwnym false. Warto pamita, e cykl ycia komponentu
prototypowego czsto rni si od cyklu ycia komponentu singletonowego. Kiedy kontener otrzymuje danie dostarczenia komponentu prototypowego, nastpuje oczywicie inicjalizacja i przekazanie odpowiedniego egzemplarza, ale na tym rola kontenera si koczy
(od tego momentu kontener nie przechowuje zwrconego egzemplarza). O ile wic istnieje
moliwo wymuszenia na kontenerze Springa wykonania pewnych operacji koczcych
cykl ycia komponentw singletonowych (patrz dalsza cz tego rozdziau), w przypadku
komponentw prototypowych te same operacje bdzie trzeba zrealizowa w kodzie uytkownika, poniewa kontener nie bdzie ju mia adnej wiedzy o zwrconych egzemplarzach
tych komponentw:

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

101

102

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


<bean id="singleton1" class="ch02.sample4.TestBean"/<
<bean id="singleton2" singleton="true" class="ch02.sample .TestBean"/<
<bean id="prototype1" singleton="false" class="ch02.sample .TestBean"/<

Definiowanie zalenoci komponentw


Spenianie zalenoci komponentw (czy to w formie innych komponentw, czy tylko prostych wartoci potrzebnych do dziaania danego komponentu) jest prawdziwym jdrem,
kluczowym elementem funkcjonalnoci kontenera, warto wic dobrze zrozumie rzeczywiste
dziaanie tego procesu. Miae ju okazj zapozna si z przykadami podstawowych typw
wstrzykiwania zalenoci, wstrzykiwaniem przez konstruktory i wstrzykiwaniem przez
metody ustawiajce, wiesz te, e Spring obsuguje obie formy tej techniki. Przekonae
si rwnie, jak Spring moe wykorzysta odpowiedni metod fabrykujc zamiast
uywa konstruktora do uzyskiwania pocztkowego egzemplarza obiektu. Wanie z uwagi
na konieczno dostarczenia zalenoci do komponentu stosowanie metody fabrykujcej do
uzyskiwania egzemplarza komponentu mona de facto uzna za odpowiednik tworzenia
egzemplarza za porednictwem konstruktora. W przypadku uycia konstruktora to kontener
odpowiada za zapewnienie wartoci (opcjonalnych) argumentw konstruktora (ktre reprezentuj zalenoci). Podobnie, w przypadku metody fabrykujcej kontener dostarcza wartoci (opcjonalnych) argumentw do metody fabrykujcej (take reprezentujce zalenoci).
Niezalenie od tego, czy pocztkowy egzemplarz obiektu jest tworzony przez konstruktor czy
przez metod fabrykujc, od tego momentu wszystkie egzemplarze s traktowane jednakowo.
Techniki wstrzykiwania przez konstruktory i wstrzykiwania przez metody ustawiajce nie
wykluczaj si wzajemnie. Nawet jeli Spring uzyskuje pocztkowy egzemplarz komponentu za porednictwem konstruktora lub metody fabrykujcej i dostarcza wartoci argumentw do konstruktora lub metody fabrykujcej (wstrzykuje zalenoci), nadal moe stosowa mechanizm wstrzykiwania przez metody ustawiajce do wprowadzania kolejnych
zalenoci. Takie rozwizanie moe by szczeglnie przydatne np. wtedy, gdy bdziemy
musieli uy i zainicjalizowa istniejc klas, ktra z jednej strony zawiera konstruktor
pobierajcy jeden lub wiele argumentw i generujcy komponent w znanym (prawidowym)
stanie pocztkowym, ale z drugiej strony bazuje na metodach ustawiajcych JavaBeans dla
czci opcjonalnych waciwoci. Gdyby nie obsuga obu form wstrzykiwania zalenoci,
nie byby w stanie prawidowo inicjalizowa tego rodzaju obiektw w sytuacji, gdyby ktra
z nich wymagaa ustawienia opcjonalnych waciwoci.
Przeanalizujmy teraz sposb, w jaki kontener inicjalizuje i realizuje zalenoci komponentw:

102

Kontener w pierwszej kolejnoci inicjalizuje definicj komponentu bez tworzenia


jego egzemplarza zwykle nastpuje to w czasie uruchamiania samego kontenera.
Zalenoci komponentu mog by wyraane wprost, w formie argumentw
konstruktora lub metody fabrykujcej i (lub) waciwoci komponentu.

Kada waciwo lub argument konstruktora w definicji komponentu ma albo posta


wartoci wymagajcej ustawienia, albo odwoania do innego komponentu w ramach
danej fabryki komponentw lub nadrzdnej fabryki komponentw.

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

103

Kontener wykona tyle operacji sprawdzajcych poprawno definiowanych zalenoci,


ile bdzie mg w czasie inicjalizacji definicji komponentu. Jeli korzystasz
z formatu konfiguracji XML, w przypadku niezgodnoci konfiguracji z typem XML
DTD w pierwszej kolejnoci otrzymamy wyjtek wygenerowany przez parser
XML. Nawet jeli konfiguracja w formacie XML jest poprawna z punktu widzenia
definicji typw DTD, w razie wykrycia logicznej niespjnoci przez Springa take
otrzymamy odpowiedni wyjtek przykadowo, dwie waciwoci mog si wzajemnie
wyklucza, czego nie da si wykaza wycznie na podstawie analizy typw DTD.

Jeli zaleno komponentu nie moe by zrealizowana w praktyce (jeli zaleno


komponentu ma posta innego komponentu, ktry nie istnieje) lub jeli argument
konstruktora lub warto waciwoci nie moe zosta prawidowo ustawiona,
otrzymamy komunikat o bdzie tylko wtedy, gdy dany kontener rzeczywicie
bdzie musia uzyska nowy egzemplarz tego komponentu i wstrzykn jego
zalenoci. Jeli okae si, e egzemplarz komponentu nigdy nie bdzie potrzebny,
nie mona wykluczy, e ewentualne bdy w definicji zalenoci komponentu lub
samego komponentu nigdy nie zostan wykryte (przynajmniej do momentu jego
uycia). Midzy innymi po to, aby umoliwi moliwie szybkie wykrywanie bdw,
konteksty aplikacji (ale nie fabryki komponentw) domylnie tworz wstpne
egzemplarze komponentw singletonowych. Faza wstpnego tworzenia egzemplarzy
obejmuje iteracyjne przeszukiwanie wszystkich komponentw singletonowych
(w ich domylnych stanach), utworzenie egzemplarzy kadej ze wstrzykiwanych
zalenoci i umieszczenie tych egzemplarzy w pamici podrcznej. Warto pamita,
e etap wstpnego tworzenia egzemplarzy komponentw mona zmodyfikowa
albo za pomoc atrybutu refault-lazy-init elementu beans definiowanego na
najwyszym poziomie pliku konfiguracji, albo na poziomie poszczeglnych
komponentw (elementw bean) za porednictwem atrybutu lazy-init.

Kiedy kontener potrzebuje nowego egzemplarza danego komponentu (zazwyczaj


w wyniku wywoania metody getBean() lub odwoania ze strony innego komponentu,
dla ktrego biecy komponent jest zalenoci), uzyskuje pocztkowy egzemplarz
za porednictwem konfigurowanego konstruktora lub metody fabrykujcej, po czym
podejmuje prby wstrzykiwania zalenoci, opcjonalnych argumentw konstruktora
lub metody fabrykujcej oraz opcjonalnych wartoci waciwoci.

Argumenty konstruktora lub waciwoci komponentu, ktre odwouj si


do innego komponentu, w pierwszej kolejnoci wymuszaj na kontenerze tworzenie
lub uzyskiwanie dostpu do tamtego komponentu. W efekcie wskazywany
komponent jest w istocie zalenoci komponentu, ktry si do niego odwouje.
Operacje tworzenia lub uzyskiwania dostpu do komponentw skadaj si na
logicznie spjny acuch, ktry mona reprezentowa w formie grafu zalenoci.

Kady argument konstruktora lub warto waciwoci musi zapewnia moliwo


konwersji z oryginalnego typu lub formatu na typ faktycznie oczekiwany przez
argument konstruktora lub waciwo komponentu (oczywicie jeli oba typy s
rne). Spring oferuje mechanizmy konwersji argumentw przekazywanych w formacie
acuchowym do wszystkich wbudowanych typw skalarnych, a wic int, long,
boolean itd., oraz wszystkich typw opakowa, w tym Integer, Long, Boolean itd.
Spring wykorzystuje te implementacje interfejsu PropertyPritor komponentw
JavaBeans do konwersji wartoci typu String na niemal dowolne typy danych.
Kontener automatycznie rejestruje i wykorzystuje wiele rnych implementacji

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

103

104

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


tego interfejsu. Przykadem takiej implementacji jest klasa ClassPritor, ktra
konwertuje acuch reprezentujcy nazw klasy na egzemplarz klasy Class, ktry
moe by przekazany do waciwoci oczekujcej takiego egzemplarza; innym
przykadem jest klasa ResourcePritor, ktra konwertuje acuch reprezentujcy
ciek lokalizacji na obiekt klasy Resource Springa, ktry moe by wykorzystywany
do abstrakcyjnego uzyskiwania dostpu do zasobw. Wszystkie wbudowane
edytory waciwoci omwimy w nastpnym rozdziale. Istnieje te moliwo
rejestrowania wasnych implementacji interfejsu PropertyPritor obsugujcych
Twoje typy niestandardowe (patrz podpunkt Tworzenie wasnych edytorw
waciwoci w dalszej czci tego rozdziau).
n

Take wariant konfiguracji oparty na formacie XML, ktry jest wykorzystywany


przez wikszo implementacji fabryk komponentw i kontekstw aplikacji,
wykorzystuje wasne elementy i atrybuty umoliwiajce definiowanie zoonych
kolekcji, czyli list, zbiorw, map i waciwoci. Okazuje si, e wartoci tych
kolekcji mog by dowolnie zagniedane.

Zalenoci mog te mie charakter niejawny w ekstremalnych przypadkach


Spring moe uy refleksji do sprawdzenia argumentw pobieranych przez
konstruktor komponentu (lub wartoci waciwoci tego komponentu) nawet wtedy,
gdy nie zadeklarowano odpowiednich zalenoci. Kontener moe na podstawie
takiej procedury zbudowa list prawidowych zalenoci danego komponentu.
Nastpnie, korzystajc z mechanizmu nazywanego wizaniem automatycznym
(ang. autowiring), kontener moe te zalenoci wypeni w oparciu o dopasowania
wedug typw lub nazw. Na razie pominiemy temat automatycznego wizania,
ale z pewnoci do niego wrcimy w dalszej czci tego rozdziau.

Definiowanie zalenoci komponentw w szczegach


W tym podpunkcie szczegowo omwimy techniki definiowania wartoci waciwoci
komponentw i argumentw konstruktorw w formacie XML. Kady element bean moe
zawiera zero, jeden lub wiele elementw constructor-arg okrelajcych argumenty konstruktora lub metody wyszukujcej. Elementy bean mog te zawiera zero, jeden lub wiele
elementw property okrelajcych waciwoci JavaBean wymagajcych ustawienia. Jeli
sytuacja tego wymaga, mona czy oba podejcia (argumenty konstruktora i waciwoci
JavaBean) takie rozwizanie zastosowano w poniszym przykadzie, gdzie argument
konstruktora jest w istocie odwoaniem do innego komponentu, natomiast waciwo typu
int jest zwyk wartoci:
<beans<
<bean id="weatherService" class="ch02.sample6.WeatherServiceImpl"<
<constructor-arg index="0"<
<ref local="weatherDao"/<
</constructor-arg<
<property name="maxRetryAttempts"<<value<2</value<</property<
</bean<
<bean id="weatherDao" class="ch02.sample6.StaticDataWeatherDaoImpl"<
</bean<
</beans<

104

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

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

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

105

106

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


sytuacji, w ktrej takie rozwizanie jest uzasadnione, jest przekazywanie acuchw reprezentujcych daty, ktre maj by nastpnie wykorzystywane do ustawiania waciwoci typu
Date. Poniewa daty s szczeglnie wraliwe na uwarunkowania regionalne, uycie odpowiedniej implementacji interfejsu PropertyPritor, ktra bdzie prawidowo obsugiwaa
acuch rdowy, jest najprostszym rozwizaniem tego problemu. Sposb rejestrowania
niestandardowych implementacji tego interfejsu zostanie przedstawiony w dalszej czci
tego rozdziau, przy okazji omawiania klasy CustomPritorConfigurer i postprocesora fabryki komponentw. Niewielu programistw zdaje sobie spraw z tego, e odpowiednie
mechanizmy interfejsu PropertyPritor automatycznie wykrywaj i wykorzystuj wszystkie
implementacje tego interfejsu, ktre nale do tego samego pakietu co klasa przeznaczona
do konwersji (jedynym warunkiem jest zgodno nazwy tej klasy z nazw klasy implementujcej wspomniany interfejs, ktra dodatkowo musi zawiera sufiks Pritor). Oznacza to, e
w przypadku klasy MyType implementacja interfejsu PropertyPritor nazwana MyTypePritor
i naleca do tego samego pakietu co klasa MyType zostanie automatycznie wykryta i uyta
przez kod pomocniczy JavaBeans zdefiniowany w odpowiedniej bibliotece Javy (bez najmniejszego udziau Springa).
Waciwoci lub argumenty konstruktora, ktrym naley przypisa warto null, wymagaj
specjalnego traktowania, poniewa pusty element value jest interpretowany jak acuch
pusty. Zamiast braku wartoci naley wic uy elementu null:
<property name="optionalDescription"<<null/<</property<

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<

Moliwie szybkie wykrywanie ewentualnych literwek w podobnych odwoaniach byoby


oczywicie korzystne element irref w praktyce odpowiada wanie za tak weryfikacj.
Uycie elementu property w postaci:
<property name="beanName"<<idref local="weatherService"/<</property<

umoliwia analizatorowi skadniowemu XML udzia we wczesnym procesie weryfikacji,


poniewa ju na etapie analizy skadniowej mona bez trudu wykry odwoania do komponentw, ktre w rzeczywistoci nie istniej. Warto wynikowa tej waciwoci bdzie dokadnie taka sama jak w przypadku uycia standardowego znacznika value.
Elementy list, set, map i props umoliwiaj definiowanie i ustawianie zoonych waciwoci
lub argumentw konstruktorw (odpowiednio typw java.util.List, java.util.Set,
java.util.Map i java.util.Properties). Przeanalizujmy teraz cakowicie nierzeczywisty
przykad, w ktrym definiowany komponent JavaBean bdzie zawiera po jednej waciwoci
kadego z wymienionych typw zoonych:
<beans<
<bean id="collectionsExample" class="ch02.sample .CollectionsBean"<
<property name="theList"<

106

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

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

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

107

108

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


typu w takim przypadku nie mona konkretnego typu kolekcji zastpi jego uniwersalnym odpowiednikiem. Jednym z rozwiza jest uycie udostpnianych przez Springa pomocniczych komponentw fabrykujcych (ang. factory beans): ListFactoryBean, SetFactoryBean lub MapFactoryBean. Za ich pomoc mona swobodnie okrela docelowy typ
kolekcji, w tym np. java.util.LinkerList. Wicej informacji na ten temat znajdziesz
w dokumentacji JavaDoc Springa. Same komponenty fabrykujce omwimy w dalszej czci
rozdziau.
Ostatnim elementem, ktry moe wystpowa w roli wartoci waciwoci lub wartoci argumentu konstruktora (lub wewntrz ktrego z opisanych przed chwil elementw kolekcji),
jest element bean. Oznacza to, e definicja komponentw moe by de facto zagniedana
w definicji innego komponentu (jako waciwo komponentu zewntrznego). Przeanalizujmy teraz przebudowany przykad wstrzykiwania przez metod ustawiajc:
<beans<
<bean id="weatherService" class="ch02.sample2.WeatherServiceImpl"<
<property name="weatherDao"<
<bean class="ch02.sample2.StaticDataWeatherDaoImpl"/<
...
</bean<
</property<
</bean<
</beans<

Zagniedone definicje komponentw s szczeglnie przydatne w sytuacji, gdy komponent


wewntrzny nie znajduje adnych zastosowa poza zakresem komponentu zewntrznego.
W porwnaniu z poprzedni wersj tego przykadu obiekt DAO (ktry ustawiono jako zaleno usugi pogodowej) zosta wczony do komponentu usugi pogodowej i przyj posta jego komponentu wewntrznego. aden inny komponent ani uytkownik zewntrzny
nie bdzie przecie potrzebowa tego obiektu DAO, zatem utrzymywanie go poza zakresem
komponentu usugi (jako osobnej, zewntrznej definicji) mijaoby si z celem. Uycie komponentu wewntrznego jest w tym przypadku rozwizaniem bardziej zwizym i klarownym.
Komponent wewntrzny nie musi mie zdefiniowanego identyfikatora, cho nie jest to zabronione. Uwaga: Komponenty wewntrzne zawsze s komponentami prototypowymi,
a ewentualny atrybut singleton jest ignorowany. W tym przypadku nie ma to najmniejszego
znaczenia poniewa istnieje tylko jeden egzemplarz komponentu zewntrznego (ktry
jest singletonem), utworzenie wicej ni jednego egzemplarza komponentu wewntrznego
jest wykluczone (niezalenie od tego, czy zadeklarujemy ten komponent jako singletonowy
czy jako prototypowy). Gdyby jednak prototypowy komponent zewntrzny potrzebowa
zalenoci singletonowej, nie powinnimy tej zalenoci definiowa w formie komponentu
wewntrznego, tylko jako odwoanie do singletonowego komponentu zewntrznego.

Samodzielne (rczne) deklarowanie zalenoci


Kiedy waciwo komponentu lub argument konstruktora odwouje si do innego komponentu,
mamy do czynienia z deklaracj zalenoci od tego zewntrznego komponentu. W niektrych sytuacjach konieczne jest wymuszenie inicjalizacji jednego komponentu przed innym,
nawet jeli ten drugi nie zosta zadeklarowany jako waciwo pierwszego. Wymuszanie
okrelonej kolejnoci inicjalizacji jest uzasadnione take w innych przypadkach, np. kiedy

108

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

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.

Automatyczne wizanie zalenoci


Do tej pory mielimy do czynienia z deklaracjami zalenoci komponentw wyraanymi
wprost (za porednictwem wartoci waciwoci i argumentw konstruktora). W pewnych
okolicznociach Spring moe uy mechanizmu introspekcji klas komponentw w ramach
biecej fabryki i przeprowadzi automatyczne wizanie zalenoci. W takim przypadku
waciwo komponentu lub argument kontenera nie musz by deklarowane (np. w pliku
XML), poniewa Spring uyje refleksji do odnalezienia typu i nazwy odpowiedniej waciwoci, po czym dopasuje j do innego komponentu w danej fabryce (wedug jego typu
lub nazwy). Takie rozwizanie moe co prawda oszczdzi programicie mnstwo pracy
zwizanej z samodzielnym przygotowywaniem odpowiedniego kodu, jednak niewtpliwym
kosztem tego podejcia jest mniejsza przejrzysto. Mechanizm automatycznego wizania
zalenoci mona kontrolowa zarwno na poziomie caego kontenera, jak i na poziomie
definicji poszczeglnych komponentw. Poniewa nieostrone korzystanie z tej techniki
moe prowadzi do nieprzewidywalnych rezultatw, mechanizm automatycznego wizania
jest domylnie wyczony. Automatyczne wizanie na poziomie komponentw jest kontrolowane za porednictwem atrybutu autowire, ktry moe zawiera pi wartoci:
n no

mechanizm automatycznego wizania zalenoci w ogle nie bdzie


stosowany dla danego komponentu. Waciwoci tego komponentu oraz argumenty
konstruktora musz by deklarowane wprost, a wszelkie odwoania do innych
komponentw wymagaj uywania elementu ref. Okazuje si, e jest to domylny
sposb obsugi poszczeglnych komponentw (przynajmniej jeli domylne
ustawienia na poziomie fabryki komponentw nie zostay zmienione). Opisany tryb
jest zalecany w wikszoci sytuacji, szczeglnie w przypadku wikszych wdroe,
gdzie zalenoci deklarowane wprost stanowi swoist dokumentacj struktury
oprogramowania i s duo bardziej przejrzyste.

n byName

wymusza automatyczne wizanie zalenoci wedug nazw waciwoci.


Nazwy waciwoci s wykorzystywane podczas odnajdywania dopasowa
do komponentw w biecej fabryce komponentw. Przykadowo, jeli dana
waciwo ma przypisan nazw weatherDao, wwczas kontener sprbuje ustawi
t waciwo jako odwoanie do innego komponentu nazwanego wanie weatherDao.

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

109

110

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


Jeli taki pasujcy komponent nie zostanie znaleziony, waciwo pozostanie
nieustawiona. Taka reakcja na brak dopasowania pomidzy nazw waciwoci
a nazw komponentu jest opcjonalna jeli chcesz traktowa brak dopasowania
jak bd, moesz do definicji komponentu doda atrybut repenrency-check="objects"
(patrz dalsza cz tego rozdziau).
n byType

automatyczne wizanie zalenoci przez dopasowywanie typw. Podobne


rozwizanie zastosowano w kontenerze PicoContainer, innym popularnym produkcie
obsugujcym wstrzykiwanie zalenoci. W przypadku kadej waciwoci jeli
w biecej fabryce komponentw istnieje dokadnie jeden komponent tego samego
typu co ta waciwo warto jest ustawiana wanie jako ten komponent. Jeli
w fabryce istnieje wicej ni jeden komponent pasujcego typu, efektem nieudanej
prby dopasowania jest bd krytyczny, ktry zwykle prowadzi do wygenerowania
odpowiedniego wyjtku. Tak jak w przypadku automatycznego wizania zalenoci
wedug nazwy (warto byName) w przypadku braku pasujcych komponentw
waciwo pozostaje nieustawiona. Jeli brak dopasowania powinien by traktowany
jak bd, wystarczy do definicji komponentu doda atrybut repenrency-check="objects"
(patrz dalsza cz tego rozdziau).

n constructor

automatyczne wizanie zalenoci wedug typw argumentw


konstruktora. Ten tryb bardzo przypomina wizanie zalenoci z waciwociami,
tyle e polega na szukaniu w fabryce dokadnie jednego pasujcego (wedug typu)
komponentu dla kadego z argumentw konstruktora. W przypadku wielu
konstruktorw Spring w sposb zachanny bdzie prbowa speni wymagania
konstruktora z najwiksz liczb pasujcych argumentw.

n autoretect

wybiera tryby byType i constructor w zalenoci od tego, ktry


z nich lepiej pasuje do danej sytuacji. W przypadku wykrycia domylnego,
bezargumentowego konstruktora stosowany jest tryb byType; w przeciwnym
razie zostanie zastosowany tryb constructor.

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

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

111

<bean id="weatherDao" class="ch02.sample2.StaticDataWeatherDaoImpl"<


</bean<
</beans<

Korzystanie z technik automatycznego wizania zalenoci jest o tyle kuszce, e zwalnia


programist z obowizku pisania znacznej iloci kodu konfiguracji fabryki komponentw,
jednak warto zachowa naleyt ostrono i stosowa ten mechanizm z rozwag.
Usuwajc zalenoci deklarowane wprost, rezygnujemy z jednej z form dokumentowania tych zalenoci. Co wicej, ze stosowaniem trybw byType lub nawet byName wie
si ryzyko nieprzewidywalnych zachowa w sytuacji, gdy uda si odnale wicej ni
jedno dopasowanie (pasujcy komponent) lub w razie braku jakiegokolwiek dopasowania. Szczeglnie w przypadku wikszych, bardziej skomplikowanych wdroe zaleca
si unikanie automatycznego wizania zalenoci szerokim ukiem lub przynajmniej
bardzo rozwane korzystanie z tego mechanizmu, poniewa w przeciwnym razie moe
si okaza, e ograniczajc ilo kodu XML, dodatkowo skomplikowalimy ca aplikacj.
Wikszo wspczesnych rodowisk IDE oferuje (wbudowane lub dostpne w formie
moduw rozszerze) edytory XML z obsug DTD, ktre mog oszczdzi mnstwo
czasu i wysiku programisty podczas tworzenia konfiguracji komponentw, zatem rozmiar deklaracji zalenoci wyraonych wprost nie stanowi wielkiego problemu. Tym, co
moe si doskonale sprawdza w pewnych sytuacjach, jest stosowanie automatycznego
wizania zalenoci dla prostych, niskopoziomowych wntrznoci (np. DataSource)
i jednoczenie deklarowanie zalenoci wprost w przypadku bardziej skomplikowanych
aspektw. W ten sposb mona wyeliminowa nadmiar pracy bez koniecznoci powicania transparentnoci.

Dopasowywanie argumentw konstruktora


Oglna zasada mwi, e dla kadego deklarowanego elementu constructor-arg naley dodatkowo stosowa opcjonalne atrybuty inrex i (lub) type. Chocia oba wymienione atrybuty s opcjonalne, w przypadku pominicia choby jednego z nich zadeklarowana lista argumentw konstruktora bdzie dopasowywana do rzeczywistych argumentw wedug ich
typw. Jeli zadeklarowane argumenty s odwoaniami do innych typw (np. skomplikowanych
komponentw lub takich typw zoonych jak java.lang.Map), kontener bdzie mg znale odpowiednie dopasowanie stosunkowo atwo, szczeglnie w sytuacji, gdy bdzie istnia tylko jeden konstruktor. Jeli jednak zadeklarujemy wiele argumentw tego samego
typu lub uyjemy znacznika value, ktry bdzie de facto wartoci bez typu (zadeklarowan
w formie acucha), prby automatycznego dopasowywania mog si zakoczy bdami
lub innymi nieprzewidywalnymi zachowaniami.
Przeanalizujmy przykad komponentu, ktry zawiera pojedynczy konstruktor pobierajcy
numeryczn warto kodu bdu oraz acuchow warto komunikatu o bdzie. Jeli sprbujemy uy znacznika <value> do dostarczania wartoci dla tych argumentw, bdziemy musieli przekaza kontenerowi jak dodatkow wskazwk odnonie realizacji tego zadania.
Moemy posuy si albo atrybutem inrex do okrelenia waciwego indeksu argumentu
(liczonego od zera), co uatwi dopasowanie przekazywanej wartoci do odpowiedniego argumentu konstruktora:
<beans<
<bean id="errorBean" class="ch02.sampleX.ErrorBean"<
<constructor-arg index="0"<<value<1000</value<</constructor-arg<

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

111

112

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


<constructor-arg index="1"<<value<Nieoczekiwany bd</value<</constructor-arg<
</bean<
</beans<

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<

Sprawdzanie poprawnoci zalenoci komponentw


Czsto si zdarza, e cz waciwoci JavaBean danego obiektu ma charakter opcjonalny.
Moesz, ale nie musisz, ustawia ich wartoci w zalenoci od tego, czy odpowiednia warto jest potrzebna w konkretnym przypadku testowym; warto jednak pamita, e kontener
nie dysponuje mechanizmami, ktre mogyby Ci pomc w wychwytywaniu bdw nieustawienia waciwoci, ktre tego wymagaj. Jeli jednak masz do czynienia z komponentem, ktrego wszystkie waciwoci (lub przynajmniej wszystkie waciwoci okrelonego typu) musz by ustawione, duym uatwieniem moe by oferowany przez kontener
mechanizm weryfikacji poprawnoci zalenoci. Jeli zdecydujemy si na uycie tego mechanizmu, kontener bdzie traktowa ewentualny brak deklaracji wprost lub automatycznego
wizania zalenoci jako bd. Kontener domylnie nie podejmuje prb takiej weryfikacji
(sprawdzania, czy wszystkie zalenoci s odpowiednio ustawione), mona jednak zmieni
to zachowanie w definicji komponentu za pomoc atrybutu repenrency-check, ktry moe
mie nastpujce wartoci:
n none

brak weryfikacji zalenoci. Jeli dla ktrej z waciwoci nie okrelono


wartoci, w przypadku braku weryfikacji taka sytuacja nie bdzie traktowana jak
bd. Jest to domylny sposb obsugi poszczeglnych komponentw (przynajmniej
jeli ustawienia domylne nie zostan zmienione na poziomie fabryki komponentw).

n simple

sprawdza, czy ustawiono typy proste i kolekcje brak wartoci w tych


waciwociach bdzie traktowany jak bd. Pozostae waciwoci mog, ale nie
musz by ustawione.

n objects

sprawdza tylko waciwoci innych typw ni typy proste i kolekcje


brak wartoci w tych waciwociach bdzie traktowany jak bd. Pozostae
waciwoci mog, ale nie musz by ustawione.

n all

sprawdza, czy ustawiono wartoci wszystkich waciwoci, w tym we


waciwociach typw prostych, kolekcjach i waciwociach typw zoonych.

Istnieje moliwo zmiany domylnego trybu sprawdzania zalenoci (ustawienie innego


trybu ni none) dla wszystkich komponentw w ramach danej fabryki wystarczy uy
atrybutu refault-repenrency-check w elemencie beans na najwyszym poziomie hierarchii.

112

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

113

Pamitaj te, e take interfejs wywoa zwrotnych InitializingBean (patrz nastpny punkt)
moe by wykorzystywany do rcznego sprawdzania poprawnoci zalenoci.

Zarzdzanie cyklem ycia komponentu


Komponent w fabryce moe si charakteryzowa zarwno bardzo prostym, jak i wzgldnie
skomplikowanym cyklem ycia wszystko zaley od tego, jaki jest zakres odpowiedzialnoci danego komponentu. Poniewa mwimy o obiektach POJO, cykl ycia komponentu
nie musi obejmowa dziaa wykraczajcych poza tworzenie i uywanie danego obiektu.
Istnieje jednak wiele sposobw zarzdzania i obsugi bardziej zoonymi cyklami ycia, z ktrych wikszo koncentruje si wok wywoa zwrotnych, gdzie sam komponent i zewntrzne obiekty obserwatorw (nazywane postprocesorami komponentu) mog obsugiwa wiele etapw procesw inicjalizacji i destrukcji. Przeanalizujmy teraz moliwe akcje
kontenera (patrz ponisza tabela), ktre mog mie miejsce w cyklu ycia komponentu zarzdzanego przez kontener.
Akcja

Opis

Inicjalizacja
rozpoczynajca si
w momencie utworzenia
egzemplarza komponentu

Egzemplarz nowego komponentu jest tworzony za porednictwem


konstruktora lub metody fabrykujcej (oba rozwizania s
rwnowane). Proces tworzenia egzemplarza komponentu jest
inicjowany przez wywoanie metody getBean() fabryki komponentw
lub przez danie ze strony innego komponentu, ktrego egzemplarz
ju istnieje i ktry zawiera zaleno od biecego komponentu.

Wstrzyknicie zalenoci

Zalenoci s wstrzykiwane do nowo utworzonego egzemplarza


komponentu (w ramach omwionej ju procedury).

Wywoanie metody

Jeli komponent implementuje opcjonalny interfejs BeanNameAware,


wwczas metoda setBeanName() naleca wanie do tego interfejsu
jest wywoywana w celu nadania komponentowi jego gwnego
identyfikatora (zadeklarowanemu w definicji komponentu).

setBeanName()

Wywoanie metody
setBeanFactory()

Wywoanie metody
setResourceLoader()

Jeli komponent implementuje opcjonalny interfejs BeanFactoryAware,


referencj do fabryki, w ramach ktrej ten komponent zosta
wdroony, mona wprowadzi do komponentu, wywoujc metod
setBeanFactory() tego interfejsu. Warto pamita, e poniewa take
konteksty aplikacji s fabrykami komponentw, wspomniana metoda
bdzie wywoywana rwnie w przypadku komponentw
wdroonych w ramach kontekstu aplikacji (jednak wwczas
komponent otrzyma odwoanie do fabryki wykorzystywanej
wewntrznie przez dany kontekst).
Jeli dany komponent implementuje opcjonalny interfejs
ResourceLoaderAware i jest wdraany w ramach kontekstu aplikacji,
przedmiotem wywoania jest metoda setResourceLoader() tego
interfejsu, z parametrem bdcym kontekstem aplikacjim ktry
implementuje interfejs ResourceLoader (to rozwizanie omwimy
ju w nastpnym rozdziale).

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

113

114

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


Akcja

Opis

Wywoanie metody

Jeli komponent implementuje opcjonalny interfejs


ApplicationEventPublisherAware i jest wdraany w ramach
kontekstu aplikacji, przedmiotem wywoania jest metoda
setApplicationEventPublisher() tego interfejsu, a parametrem
jest kontekst aplikacji, ktry implementuje interfejs
ApplicationEventPublisher (take to rozwizanie omwimy
w nastpnym rozdziale).

setApplicationEventPublisher()

Wywoanie metody
setMessageSource()

Wywoanie metody
setApplicationContext()

Jeli dany komponent implementuje opcjonalny interfejs


ApplicationContextAware i jest wdraany w ramach kontekstu
aplikacji, zapewnienie komponentowi referencji do tego kontekstu
wymaga wywoania metody setApplicationContext(), ktra jest
czci interfejsu ApplicationContextAware.

Przekazanie
postprocesorom
komponentu wywoania
zwrotnego przed
inicjalizacj

Postprocesory komponentu (ktre omwimy w dalszej czci


tego rozdziau) s specjalnymi rozwizaniami pomocniczymi
rejestrowanymi przez aplikacj wraz z fabrykami komponentw.
Postprocesory otrzymuj wraz z wywoaniami zwrotnymi
(poprzedzajcymi waciw inicjalizacj) komponent, ktry mog
dowolnie przetwarza.

Wywoanie metody

Jeli komponent implementuje interfejs InitializingBean,


nastpuje wywoanie definiowanej przez ten interfejs metody
afterPropertiesSet(), ktra umoliwia komponentowi samodzieln
inicjalizacj.

afterPropertiesSet()

114

Jeli komponent implementuje opcjonalny interfejs


MessageSourceAware i jest wdraany w ramach kontekstu aplikacji,
przedmiotem wywoania jest naleca do tego interfejsu metoda
setResourceLoader(), a przekazywany jest kontekst aplikacji, ktry
implementuje interfejs MessageSource (take to rozwizanie
omwimy w nastpnym rozdziale).

Wywoanie
zadeklarowanej metody
inicjalizujcej

Jeli definicja danego komponentu zawiera deklaracj metody


inicjalizujcej (w formie odpowiedniej wartoci atrybutu
init-method), wanie ta metoda zostanie wywoana,
aby umoliwi komponentowi samodzieln inicjalizacj.

Przekazanie postprocesorom
komponentu wywoania
zwrotnego po inicjalizacji
z argumentem zawierajcym
egzemplarz komponentu

Kady postprocesor komponentu otrzymuje wywoanie zwrotne


po inicjalizacji z doczonym (w formie argumentu)
egzemplarzem komponentu, ktry w razie potrzeby
moe dowolnie przetwarza.

Uycie komponentu

Na tym etapie egzemplarz komponentu jest przedmiotem waciwych


operacji. Oznacza to, e komponent jest zwracany do kodu obiektu
wywoujcego metod getBean() i wykorzystywany do ustawienia
waciwoci pozostaych komponentw (ktre wywoay biecy
komponent jako swoje zalenoci) itd. Wana uwaga: Tylko cykl
ycia komponentw singletonowych jest od tego momentu ledzony
przez kontener, natomiast wacicielami komponentw prototypowych
s obiekty klienckie, ktre z nich korzystaj. Kontener bdzie wic
uczestniczy w przyszych zdarzeniach zwizanych tylko z cyklem
ycia komponentw singletonowych. Od tego momentu wszystkie
komponenty prototypowe musz by w caoci zarzdzane przez
swoich klientw (dotyczy to take wywoania metody niszczcej).

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

115

Akcja

Opis

Rozpoczcie procedury
destrukcji komponentu

W ramach procesu koczenia pracy fabryki komponentw lub


kontekstu aplikacji (ktry obejmuje trzy opisane poniej kroki)
naley zniszczy wszystkie skadowane w pamici podrcznej
komponenty singletonowe. Naley pamita, e komponenty s
niszczone w kolejnoci odpowiadajcej wystpujcymi midzy nimi
zalenociami (najczciej w kolejnoci odwrotnej do inicjalizacji).

Przekazanie
postprocesorom
komponentu wywoania
zwrotnego zniszcz
Wywoanie metody
destroy()

Wywoanie
zadeklarowanej metody
niszczcej

Kady postprocesor komponentu implementujcy interfejs


DestructionAwareBeanPostProcessor otrzymuje wywoanie zwrotne,

ktre umoliwia mu przygotowanie komponentu singletonowego


do zniszczenia.
Jeli komponent singletonowy implementuje interfejs
DisposableBean, wwczas jest wywoywana metoda destroy()
tego interfejsu, ktra umoliwia komponentowi wykonanie
wszystkich niezbdnych operacji zwalniania zasobw.
Jeli definicja komponentu singletonowego zawiera deklaracj
metody niszczcej (w formie wartoci atrybutu destroy-method),
odpowiednia metoda jest wywoywana na samym kocu, a jej
dziaania najczciej sprowadzaj si do zwalniania wszystkich
zasobw, ktre tego wymagaj.

Wywoania zwrotne inicjalizacji i destrukcji


Wspomniane przed chwil metody inicjalizujce i niszczce mog by wykorzystywane do
wykonywania wszystkich niezbdnych operacji w zakresie rezerwowania i zwalniania zasobw dla danego komponentu. W przypadku istniejcych klas, ktre zawieraj ju unikatowo nazwane metody inicjalizujce i niszczce, jedynym skutecznym rozwizaniem jest
uycie atrybutw init-methor i restroy-methor wymuszajcych na kontenerze wywoywanie tych metod we waciwych momentach patrz poniszy przykad, gdzie konieczne
jest wywoanie metody close() zastosowanej w implementacji DataSource (korzystajcej
z Jakarta Commons DBCP):
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroymethod="close"<
<property name="driverClassName"<
<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<

Oglnie nawet podczas budowania nowego oprogramowania zaleca si stosowanie atrybutw


init-methor i restroy-methor, ktre zasygnalizuj kontenerowi konieczno wywoania
odpowiednich metod inicjalizujcych i niszczcych takie rozwizanie jest pod wieloma
wzgldami lepsze od implementowania przez sam komponent interfejsw InitializingBean

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

115

116

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


i DisposableBean Springa z ich metodami afterPropertiesSet() i restroy(). To drugie podejcie jest z jednej strony wygodne, poniewa wspomniane interfejsy s automatycznie
wykrywane przez Springa, co oznacza, e take wymienione metody s wywoywane przez
ten framework bez udziau programisty, z drugiej strony niepotrzebnie wie Twj kod z kontenerem Springa. Jeli kod aplikacji jest zwizany ze Springiem take z innych powodw
i w innych punktach, ta dodatkowa zaleno nie stanowi wikszego problemu, a stosowanie
interfejsw InitializingBean i DisposableBean jednoczenie jest niemaym uatwieniem
dla programisty. Okazuje si, e take kod samego Springa, ktry jest wdraany w formie
komponentw, czsto wykorzystuje oba interfejsy.
Jak ju wspomniano, po zakoczeniu fazy inicjalizacji niesingletonowe, prototypowe komponenty nie s skadowane ani zarzdzane w kontenerze. Oznacza to, e w przypadku tych
komponentw Spring nie ma adnych moliwoci ani w zakresie wywoywania metod
niszczcych, ani w kwestii jakichkolwiek innych dziaa zwizanych z cyklem ycia komponentw (waciwych tylko dla zarzdzanych przez kontener komponentw singletonowych). Kada taka metoda musi by wywoywana z poziomu kodu uytkownika. Co wicej,
postprocesory nie mog przetwarza komponentw znajdujcych si w fazie niszczenia.

Wywoania zwrotne interfejsw BeanFactoryAware i ApplicationContextAware


Komponent, ktry z jakiego wzgldu musi mie dostp do danych i mechanizmw swojej
fabryki komponentw lub kontekstu aplikacji, moe implementowa odpowiednio interfejs
BeanFactoryAware i ApplicationContextAware. Z przedstawionej przed chwil tabeli prezentujcej kolejno akcji podejmowanych przez kontener i zwizanych z cyklem ycia
komponentu wynika, e referencje do kontenerw s przekazywane do komponentw za
porednictwem metod setBeanFactory() i setApplicationContext() (definiowanych przez
wspomniane interfejsy). Oglnie, wikszo kodu aplikacji w ogle nie powinna do prawidowego funkcjonowania potrzebowa informacji o swoich kontenerach, jednak w kodzie
cile zwizanym ze Springiem takie rozwizanie moe si okaza bardzo przydatne (tego
rodzaju wywoania zwrotne s stosowane midzy innymi w klasach samego Springa). Jednym z przypadkw, w ktrych kod aplikacji moe wymaga referencji do fabryki komponentu, jest komponent singletonowy wsppracujcy z komponentami prototypowymi. Poniewa zalenoci komponentu singletonowego s do niego wstrzykiwane tylko raz, tak
stosowany mechanizm wstrzykiwania wyklucza moliwo uzyskiwania nowych egzemplarzy komponentw prototypowych w czasie wykonywania waciwych zada (a wic po
fazie inicjalizacji). Oznacza to, e jednym ze skutecznych rozwiza tego problemu jest
bezporedni dostp do fabryki tego komponentu. Wydaje si jednak, e w wikszoci przypadkw jeszcze lepszym wyjciem jest uycie wspominanej ju techniki wstrzykiwania
metody wyszukujcej, ktra dodatkowo zapewnia izolacj klasy od mechanizmw Springa
i nazwy komponentu prototypowego.

Abstrakcja dostpu do usug i zasobw


Istnieje co prawda duo wicej zaawansowanych funkcji oferowanych przez fabryki komponentw i konteksty aplikacji, o ktrych do tej pory nawet nie wspominalimy, jednak
udao nam si przeanalizowa niemal wszystkie niskopoziomowe elementy skadowe niezbdne do skutecznego programowania i wdraania rozwiza IoC. Przekonalimy si, jak

116

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

117

obiekty aplikacji mog realizowa swoje zadania wycznie we wsppracy z pozostaymi


obiektami udostpnianymi przez kontener (za porednictwem odpowiednich interfejsw i abstrakcyjnych nadklas) bez koniecznoci dostosowywania swoich zachowa do implementacji
lub kodu rdowego tych obiektw. Wiedza przekazana do tej pory powinna Ci w zupenoci wystarczy do realizacji typowych scenariuszy korzystania z technik wstrzykiwania
zalenoci.
Tym, co moe jeszcze budzi pewne wtpliwoci, jest rzeczywisty sposb uzyskiwania pozostaych obiektw wsppracujcych (o ktrych wiesz, e mog by konfigurowane i udostpniane na rozmaite sposoby). Aby zrozumie, jak Spring chroni nas przed potencjalnymi
zawiociami i jak radzi sobie z transparentnym zarzdzaniem tego rodzaju usugami, przeanalizujmy kilka ciekawych przykadw.
Wyobra sobie nieco zmieniony obiekt DAO naszej usugi pogodowej, ktry zamiast wykorzystywa dane statyczne uywa JDBC do uzyskiwania historycznych informacji pogodowych z bazy danych. Wstpna implementacja takiego rozwizania moe wykorzystywa
oryginalny interfejs DriverManager JDBC 1.0 i za jego porednictwem uzyskiwa niezbdne
poczenie patrz metoda finr():
public WeatherData find(Date date) {
// Zwr uwag, e w konstruktorze lub metodzie inicjalizujcej uylimy
// wywoania Class.forName(driverClassName) do zarejestrowania
// sterownika JDBC. Wraz z nazw uytkownika i hasa wspomniany
// sterownik zosta skonfigurowany jako waciwoci tego komponentu.
try {
Connection con = DriverManager.getConnection(url, username, password);
// od tego miejsca moemy uywa tego poczenia
...

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.

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

117

118

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


Warto jednak pamita, e angaowanie interfejsu DataSource w proces uzyskiwania pocze z baz danych wprowadza dodatkow zoono, poniewa tworzenie i uzyskiwanie
samego egzemplarza implementacji tego interfejsu moe si odbywa na wiele rnych
sposobw. Przykadowo, implementacja DataSource dla Commons DBCP ma posta prostego komponentu JavaBean wypenianego kilkoma waciwociami konfiguracyjnymi,
natomiast w wikszoci rodowisk kontenerw J2EE egzemplarz interfejsu DataSource
uzyskuje si za porednictwem interfejsu JNDI i wykorzystuje w ramach sekwencji kodu
podobnej do tej, ktr przedstawiono poniej:
try {
InitialContext context = new InitialContext();
DataSource ds = (DataSource)context.lookup("java:comp/env/jdbc/datasource");
// od tego miejsca moemy uywa egzemplarza DataSource
...
}
catch (NamingException e) {
// obsuguje wyjtek nazewnictwa w przypadku braku danego zasobu
}

Pozostae implementacje DataSource mog wymaga stosowania zupenie innej strategii


tworzenia i dostpu.
By moe nasz obiekt DAO mgby sam wybiera waciwy sposb tworzenia lub uzyskiwania poszczeglnych typw implementacji interfejsu DataSource by moe wybr odpowiedniej implementacji powinien by jednym z elementw konfiguracji. Poniewa wiemy ju co nieco o Springu i technice odwracania kontroli (IoC), doskonale zdajemy sobie
spraw, e nie byoby to najlepsze rozwizanie, poniewa niepotrzebnie wizaoby nasz
obiekt DAO z implementacj DataSource i tym samym utrudnioby konfiguracj i bardzo
skomplikowao proces testowania. Do oczywistym rozwizaniem jest uczynienie z implementacji interfejsu DataSource waciwoci naszego DAO, ktr bdzie mona wstrzykiwa do tego obiektu z poziomu kontenera Springa. Takie podejcie doskonale zdaje egzamin w przypadku implementacji DataSource w wersji Commons DBCP, gdzie tworzony
egzemplarz tego interfejsu jest w prosty sposb wstrzykiwany do obiektu DAO:
public class JdbcWeatherDaoImpl implements WeatherDao {
DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}

public WeatherData find(Date date) {


try {
Connection con = dataSource.getConnection();
// od tego miejsca moemy uywa tego poczenia
...
}
...

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroymethod="close"<


<property name="driverClassName"<

118

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

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<

Analiza komponentw fabrykujcych


JnriObjectFactoryBean jest przykadem komponentu fabrykujcego. Komponenty fabrykujce Springa bazuj na bardzo prostej koncepcji najprociej mwic, komponent fabrykujcy to taki, ktry na danie generuje inny obiekt. Wszystkie komponenty fabrykujce Springa implementuj interfejs org.springframework.beans.factory.FactoryBean.
Magia tego rozwizania tkwi we wprowadzeniu kolejnego poziomu poredniczenia. Sam
komponent fabrykujcy jest tak naprawd zwykym komponentem JavaBean. Wdraajc
komponent fabrykujcy (tak jak kady inny komponent JavaBean), musimy okreli waciwoci i argumenty konstruktora niezbdne do prawidowego funkcjonowania tego komponentu. Okazuje si jednak, e kiedy inny komponent w ramach tego samego kontenera
odwouje si do tego komponentu fabrykujcego (za porednictwem elementu <ref>) lub
kiedy programista rcznie zada tego komponentu (za porednictwem wywoania metody
getBean()), kontener nie zwraca samego komponentu fabrykujcego wykrywa, e ma do
czynienia z komponentem fabrykujcym (za pomoc odpowiedniego interfejsu) i zamiast
egzemplarza tego komponentu zwraca utworzony przez niego obiekt. Oznacza to, e z punktu

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

119

120

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


widzenia zalenoci kady komponent fabrykujcy w istocie moe by traktowany jak
obiekt, ktry jest przez niego zwracany. Przykadowo, w przypadku komponentu JnriObjectFactoryBean tym obiektem jest obiekt odnaleziony w rodowisku JNDI (w naszym przykadzie egzemplarz implementacji interfejsu DataSource).
Interfejs FactoryBean jest bardzo prosty:
public interface FactoryBean {
Object getObject() throws Exception;
Class getObjectType();
boolean isSingleton();
}

Wywoywana przez kontener metoda getObject() zwraca obiekt wynikowy. Metoda


isSingleton() informuje, czy w kolejnych wywoaniach metody getObject() bdzie zwracany ten sam egzemplarz obiektu czy wiele rnych egzemplarzy. I wreszcie metoda getObjectType() pozwala okreli typ zwrconego obiektu (lub warto null, jeli typ tego
obiektu nie jest znany). Komponenty fabrykujce s co prawda normalnie konfigurowane
i wdraane w kontenerach, jednak s take komponentami JavaBeans, zatem w razie
koniecznoci mona z nich korzysta take programowo.
Warto si zastanowi, jak to moliwe, e komponent fabrykujcy jest uzyskiwany za
porednictwem wywoania metody getBean(), skoro odpowiedzi na danie pobrania
komponentu fabrykujcego jest jaki inny obiekt wynikowy. Kluczem jest specjalny
mechanizm, ktry sygnalizuje kontenerowi, e chodzi o sam komponent fabrykujcy,
a nie generowany przez niego obiekt wynikowy wystarczy poprzedzi identyfikator
komponentu znakiem &:
FactoryBean facBean = (FactoryBean)appContext.getBean("&dataSource");

Tworzenie wasnych, niestandardowych komponentw fabrykujcych jest bardzo proste.


Warto jednak pamita, e Spring zawiera wiele przydatnych implementacji tego typu komponentw, ktre oferuj abstrakcje dostpu do wikszoci tych popularnych zasobw i usug,
w przypadku ktrych stosowanie komponentw fabrykujcych przynosi okrelone korzyci.
Poniej przedstawiono do okrojon list tych implementacji:
n JnriObjectFactoryBean zwraca obiekt bdcy wynikiem operacji wyszukiwania JNDI.
n ProxyFactoryBean

opakowuje istniejcy obiekt wewntrz odpowiedniego


porednika, ktry jest nastpnie zwracany w odpowiedzi na danie. Rzeczywiste
funkcjonowanie tego porednika zaley od konfiguracji zdefiniowanej przez
uytkownika moe obejmowa przechwytywanie i modyfikowanie zachowania
obiektu, przeprowadzanie testw bezpieczestwa itd. Techniki stosowania tego
komponentu fabrykujcego omwimy bardziej szczegowo w rozdziale powiconym
frameworkowi programowania aspektowego (AOP) oferowanemu w ramach Springa.

n TransactionProxyFactoryBean

specjalizacja klasy ProxyFactoryBean,


ktra opakowuje obiekt transakcyjnym porednikiem.

120

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

121

n RmiProxyFactoryBean

tworzy porednik obsugujcy przezroczysty dostp do


zdalnego obiektu za porednictwem technologii zdalnego wywoywania metod
(RMI). Podobne obiekty poredniczce, tyle e dla dostpu do zdalnych obiektw
przez protokoy HTTP, JAX-RPC, Hessian i Burlap s tworzone odpowiednio
przez klasy HttpInvokerProxyFactoryBean, JaxRpcPortProxyFactoryBean,
HessianProxyFactoryBean i BurlapProxyFactoryBean. We wszystkich przypadkach
klient nie musi dysponowa adn wiedz o poredniku wystarczy przystosowanie
do wsppracy z interfejsem biznesowym.

n LocalSessionFactoryBean

konfiguruje i zwraca obiekt SessionFactory


frameworka Hibernate. Istniej podobne klasy take dla innych mechanizmw
zarzdzania zasobami, w tym JDO i iBatis.

n LocalStatelessSessionProxyFactoryBean i SimpleRemoteStatelessSessionProxyFactoryBean

tworz obiekt porednika wykorzystywany do uzyskiwania dostpu odpowiednio


do lokalnych lub zdalnych bezstanowych komponentw sesyjnych EJB. Sam klient
wykorzystuje tylko interfejs biznesowy (bez koniecznoci obsugi dostpu do JNDI
lub interfejsw EJB).
n MethorInvokingFactoryBean

zwraca wynik wywoania metody innego


komponentu, natomiast klasa FielrRetrievingFactoryBean zwraca warto pola
nalecego do innego komponentu.

Wiele komponentw fabrykujcych zwizanych z technologi JMS zwraca jej zasoby.

Podsumowanie i efekt kocowy


W poprzednich punktach przekonalimy si, e konfigurowanie obiektw z wykorzystaniem
technik IoC jest bardzo proste. Zanim jednak przystpimy do wzajemnego wizania obiektw, musimy te obiekty najpierw utworzy lub uzyska. W przypadku kilku potencjalnych
obiektw wsppracujcych (nawet jeli s ostatecznie udostpniane i konfigurowane za
porednictwem standardowego interfejsu) sam fakt tworzenia i uzyskiwania rozmaitych
obiektw za pomoc skomplikowanych i niestandardowych mechanizmw moe stanowi
przeszkod w efektywnym przetwarzaniu obiektw. Okazuje si, e mona t przeszkod
wyeliminowa za pomoc komponentw fabrykujcych. Po pocztkowych fazach tworzenia i wizania obiektw produkty generowane przez komponenty fabrykujce (osadzane
w porednikach i innych podobnych obiektach opakowa) mog peni funkcj adaptera
mog pomaga w budowie abstrakcji ponad rzeczywistymi zasobami i usugami oraz zapewnia dostp do zupenie niepodobnych usug za porednictwem podobnych interfejsw.
Jak wiemy, rda danych mona dowolnie wymienia bez koniecznoci umieszczania
w kodzie klienta (w analizowanym przykadzie t funkcj peni obiekt weatherDao) jakichkolwiek zapisw uzaleniajcych od stosowanej technologii przykadowo, zastpilimy
oryginaln implementacj interfejsu DataSource opart na Commons DBCP (majc posta
lokalnego komponentu) implementacj interfejsu DataSource waciw dla technologii JNDI.
Taka zamiana jest moliwa nie tylko dziki mechanizmowi IoC, ale take dziki wyprowadzeniu operacji dostpu do zasobw poza kod aplikacji i tym samym przygotowaniu
waciwej struktury dla technik IoC.

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

121

122

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie

Mamy nadziej, e dostrzegasz dwie najwaniejsze zalety omawianego mechanizmu


z jednej moliwo atwego abstrahowania od usug i zasobw, z drugiej strony moliwo wymiany jednego rozwizania na inne bez koniecznoci wykorzystywania sposobw wdroenia i technologii, ktrych stosowanie podczas budowy wielu aplikacji najzwyczajniej w wiecie mija si z celem. Cech wyrniajc Springa jest niezaleno
kodu klienta zarwno od faktycznego wdroenia, jak i od uytego sposobu implementacji.

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.

Wielokrotne wykorzystywanie tych samych definicji komponentw


W porwnaniu z iloci kodu Javy niezbdnego do penej konfiguracji i deklaracji wszystkich zalenoci definicje komponentw wyraane w jzyku XML wydaj si do zwize.
Nie mona jednak wykluczy, e bdziemy zmuszeni do opracowania wielu definicji komponentw, ktre w zdecydowanej wikszoci bd do siebie bardzo podobne.
Przeanalizuj nastpujc definicj komponentu WeatherService:
<bean id="weatherService" class="ch02.sample2.WeatherServiceImpl"<
<property name="weatherDao"<
<ref local="weatherDao"/<
</property<
</bean<

W typowym scenariuszu budowy aplikacji, gdzie nieodcznym elementem zaplecza jest


relacyjna baza danych, musielibymy korzysta z podobnych obiektw usug w sposb bardziej transakcyjny. Szczegowe omwienie tego zagadnienia znajdziesz w rozdziale 6.

122

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

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"<

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

123

124

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


<props<
<prop key="*"<PROPAGATION_REQUIRED</prop<
</props<
</property<
</bean<

Nastpnym krokiem jest utworzenie waciwych porednikw za pomoc odpowiednich


definicji potomnych, ktre bd obejmoway tylko waciwoci odrniajce tych porednikw od ich wsplnego, macierzystego szablonu (w tym przypadku komponentu txProxyTemplate):
<bean id="weatherServiceTarget" class="ch02.sample2.WeatherServiceImpl"<
<property name="weatherDao"<
<ref local="weatherDao"/<
</property<
</bean<
<bean id="weatherService" parent="txProxyTemplate"<
<property name="target"<<ref local="weatherServiceTarget"/<</property<
</bean<

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

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

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.

Cechy charakterystyczne definicji komponentw potomnych


Definicja komponentu potomnego dziedziczy wartoci waciwoci i argumenty konstruktora zadeklarowane w definicji komponentu macierzystego (przodka, rodzica). Okazuje si,
e komponent potomny dziedziczy po definicji komponentu macierzystego take wiele
opcjonalnych atrybutw (oczywicie pod warunkiem, e zadeklarowano je w definicji macierzystej). Zapewne zauwaye w poprzednim przykadzie, e do wskazywania identyfikatora komponentu macierzystego w definicji komponentu potomnego suy atrybut parent.
Definicja komponentu potomnego moe wskazywa konkretn klas lub pozostawia odpowiedni atrybut nieustawiony i tym samym odziedziczy jego warto po definicji
komponentu macierzystego. Warto pamita, e jeli definicja potomka okrela wasn klas
(inn ni definicja komponentu macierzystego), nowa klasa musi prawidowo obsugiwa
wszystkie argumenty konstruktora i (lub) waciwoci zadeklarowane w definicji rodzica,
poniewa zostan one odziedziczone i uyte.
Potomek dziedziczy co prawda po swoim komponencie macierzystym wartoci argumentw konstruktora, wartoci waciwoci i metody, jednak w razie potrzeby moe dodawa take nowe, wasne wartoci. Z drugiej strony, dziedziczone przez komponent potomny wartoci atrybutw init-methor, restroy-methor lub factory-methor s w caoci
przykrywane przez odpowiednie wartoci tego potomka.
Niektre ustawienia konfiguracyjne komponentu macierzystego nigdy nie s dziedziczone
i zawsze s okrelane w oparciu o definicj biecego (potomnego) komponentu. Nale do nich
wartoci atrybutw repenrs-on, autowire, repenrency-check, singleton oraz lazy-init.
Egzemplarze komponentw oznaczonych jako abstrakcyjne (za pomoc atrybutu abstract
patrz powyszy przykad) jako takie nie mog by tworzone. Jeli nie przewidujesz sytuacji, w ktrej bdzie konieczne stworzenie egzemplarza komponentu macierzystego, zawsze
powiniene go oznacza jako komponent abstrakcyjny. Naley to traktowa jak dobr
praktyk, poniewa egzemplarze nieabstrakcyjnego komponentu macierzystego mog by
tworzone przez kontener nawet wtedy, gdy tego nie zadamy ani nie uyjemy adnej zalenoci wskazujcej na ten komponent. Konteksty aplikacji (ale nie fabryki komponentw)
domylnie podejmuj prby utworzenia wstpnego egzemplarza dla kadego nieabstrakcyjnego komponentu singletonowego.
Warto pamita, e nawet jeli nie uyjemy atrybutu abstract wprost, definicje komponentw mog by niejawnie interpretowane jako abstrakcyjne ze wzgldu na brak
klasy lub metody fabrykujcej, czyli de facto brak informacji niezbdnych do utworzenia
ich egzemplarzy. Kada prba utworzenia egzemplarza abstrakcyjnego komponentu
spowoduje bd (niezalenie od tego, czy podjto j na danie programisty czy w sposb niejawny przez ktry z mechanizmw kontenera).

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

125

126

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie

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;
}

Interfejs BeanPostProcessor jest rozszerzany przez interfejs DestructionAwareBeanPostProcessor:


public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {
void postProcessBeforeDestruction(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

System.out.println("Zainicjalizowano komponent '" + beanName + "'");


return bean;

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

127

Przedstawiony przykad nie jest zbyt skomplikowany rzeczywiste postprocesory


najczciej przetwarzaj i zmieniaj egzemplarze komponentw, a informacje o rejestrowanych zdarzeniach s zapisywane w pliku dziennika, a nie na konsoli.
W kontekcie aplikacji postprocesory komponentw s rozpoznawane i wykorzystywane przez kontener automatycznie, a ich wdraanie przebiega dokadnie tak jak w przypadku wszystkich innych komponentw:
<beans<
<bean id="weatherService" class="ch02.sample2.WeatherServiceImpl"<
<property name="weatherDao"<
<ref local="weatherDao"/<
</property<
</bean<
<bean id="weatherDao" class="ch02.sample2.StaticDataWeatherDaoImpl"/<
<bean id="beanInitLogger" class="ch02.sample8.BeanInitializationLogger"/>
</beans<

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();

Jak wida, do utworzenia wstpnych egzemplarzy komponentw singletonowych w danej


fabryce uyto metody BeanFactory.preInstantiateSingletons(), poniewa domylnie tylko konteksty aplikacji tworz wstpne egzemplarze singletonw. Tak czy inaczej postprocesor jest wywoywany w momencie, w ktrym egzemplarz danego komponentu faktycznie
jest tworzony, niezalenie od tego, czy w ramach procesu przygotowywania wstpnych egzemplarzy czy w odpowiedzi na konkretne danie (jeli wspomniany proces zostanie pominity).

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

127

128

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie

Postprocesory fabryk komponentw


Postprocesory fabryk komponentw implementuj interfejs BeanFactoryPostProcessor:
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException;
}

Poniej przedstawiono przykad postprocesora fabryki komponentw, ktrego dziaanie


sprowadza si do pobrania i wywietlenia listy nazw wszystkich komponentw w danej fabryce:
public class AllBeansLister implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory factory)
throws BeansException {

System.out.println("Fabryka zawiera nastpujce komponenty:");


String[] beanNames = factory.getBeanDefinitionNames();
for (int i = 0; i < beanNames.length; ++i)
System.out.println(beanNames[i]);

Samo uywanie postprocesorw fabryki komponentw nie rni si zbytnio od stosowania


postprocesorw komponentw. Ich wdraanie w kontekcie aplikacji przebiega tak samo
jak w przypadku wszystkich innych komponentw postprocesory zostan automatycznie
wykryte i uyte przez kontekst aplikacji. Z drugiej strony, w przypadku zwykej fabryki
komponentw postprocesor musi by uruchomiony rcznie:
XmlBeanFactory factory = new XmlBeanFactory(
new ClassPathResource("ch02/sample8/beans.xml"));
AllBeansLister lister = new AllBeansLister();
lister.postProcessBeanFactory(factory);

Przeanalizujmy teraz kilka najbardziej przydatnych postprocesorw komponentw i fabryk


komponentw oferowanych w ramach Springa.

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

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

129

z pliku zewntrznego (w formacie Java Properties). Co wicej, mechanizm konfiguracyjny


domylnie bdzie weryfikowa te acuchy pod ktem zgodnoci z waciwociami systemowymi Javy, jeli nie znajdzie odpowiednich dopasowa w pliku zewntrznym. Tryb takiej
dodatkowej weryfikacji mona wcza i wycza za pomoc waciwoci systemPropertiesMore konfiguratora (ktra oferuje te moliwo wymuszania pierwszestwa dopasowa do
waciwoci System Properties wzgldem zapisw zewntrznego pliku waciwoci).
Dobrym przykadem wartoci, ktre warto wyprowadzi poza skomplikowane pliki konfiguracyjne, s acuchy konfiguracyjne waciwe dla puli pocze z baz danych. Poniej
przedstawiono ponownie fragment kodu definiujcego implementacj DataSource korzystajc z Commons DBCP tym razem uyto acuchw zastpczych zamiast rzeczywistych wartoci:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroymethod="close"<
<property name="driverClassName"<<value<${db.driverClassName}</value<</property<
<property name="url"<<value<${db.url}</value<</property<
<property name="username"<<value<${db.username}</value<</property<
<property name="password"<<value<${db.password}</value<</property<
</bean<

Rzeczywiste wartoci bd pochodziy z zewntrznego pliku waciwoci nazwanego


jdbc.properties:
db.driverClassName=oracle.jdbc.driver.OracleDriver
db.url=jdbc:oracle:thin:@db-server:1 21:devdb
db.username=john
db.password=password

Aby uy egzemplarza klasy PropertyPlaceholrerConfigurer i za jej pomoc wydoby


waciwe wartoci z pliku waciwoci do kontekstu aplikacji, wystarczy wdroy ten egzemplarz tak jak kady inny komponent:
<bean id="placeholderConfig"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"<
<property name="location"<<value<jdbc.properties</value<</property<
</bean<

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

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

129

130

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


waciwoci, o tyle PropertyOverrireConfigurer umoliwia przykrywanie tymi wartociami
wartoci waciwoci komponentw w fabryce komponentw lub kontekcie aplikacji.
Kady wiersz pliku waciwoci musi mie nastpujcy format:
beanName.property=value

gdzie beanName reprezentuje identyfikator komponentu, property jest jedn z waciwoci


tego komponentu, a value reprezentuje docelow warto tej waciwoci. Plik waciwoci
moe zawiera np. nastpujce zapisy:
dataSource.driverClassName=oracle.jdbc.driver.OracleDriver
dataSource.url=jdbc:oracle:thin:@db-server:1 21:devdb
dataSource.username=john
dataSource.password=password

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).

Tworzenie wasnych edytorw waciwoci


Czstym powodem stosowania wasnych, niestandardowych edytorw waciwoci jest konieczno ustawiania waciwoci typu java.util.Date, ktrych wartoci rdowe zapisano w postaci acuchw. Poniewa formaty dat bardzo czsto s uzalenione od ustawie
regionalnych, uycie egzemplarza PropertyPritor eksportujcego okrelony format acucha rdowego jest najprostszym sposobem radzenia sobie z problemem niezgodnoci
formatw. Poniewa utrudnienia zwizane z formatami dat dotycz wikszoci uytkownikw, zamiast prezentowa jaki abstrakcyjny przykad, posuymy si klas CustomDatePritor (implementacj PropertyPritor dla typu Date) przeanalizujemy nie tylko kod tej
klasy, ale take techniki jej rejestrowania i wykorzystywania w praktyce. Wasne edytory
waciwoci powinny by implementowane i rejestrowane w bardzo podobny sposb:
public class CustomDateEditor extends PropertyEditorSupport {
private final DateFormat dateFormat;
private final boolean allowEmpty;

130

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

131

public CustomDateEditor(DateFormat dateFormat, boolean allowEmpty) {


this.dateFormat = dateFormat;
this.allowEmpty = allowEmpty;
}
public void setAsText(String text) throws IllegalArgumentException {
if (this.allowEmpty && !StringUtils.hasText(text)) {
// traktuje pusty acuch jak warto null
setValue(null);
}
else {
try {
setValue(this.dateFormat.parse(text));
}
catch (ParseException ex) {
throw new IllegalArgumentException("Konwersja daty nie powioda si: " +
ex.getMessage());
}
}
}

public String getAsText() {


return (getValue() == null ? "" : this.dateFormat.format((Date)getValue()));
}

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.

Rejestrowanie i uywanie wasnych, niestandardowych edytorw waciwoci


Przyjrzyjmy si teraz definicji kontekstu aplikacji, w ktrej uyto postprocesora CustomPritorConfigurer do zarejestrowania edytora CustomDatePritor (implementacji uniwersalnego edytora PropertyPritor), ktrego zadaniem jest konwersja acuchw znakowych na
obiekty klasy java.util.Date. Definicja konfiguracji zawiera konkretny format acuchw
reprezentujcych daty:

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

131

132

Spring Framework. Profesjonalne tworzenie oprogramowania w Javie


<bean id="customEditorConfigurer"
class="org.springframework.beans.factory.config.CustomEditorConfigurer"<
<property name="customEditors"<
<map<
<!-- rejestruje edytor waciwoci dla typu java.util.Date -->
<entry key="java.util.Date"<
<bean class="org.springframework.beans.propertyeditors.CustomDateEditor"<
<constructor-arg index="0"<
<bean class="java.text.SimpleDateFormat"<
<constructor-arg<<value<M/d/yy</value<</constructor-arg<
</bean<
</constructor-arg<
<constructor-arg index="1"<<value<true</value<</constructor-arg<
</bean<
</entry<
</map<
</property<
</bean<
<!-- sprawdza funkcjonowanie edytora dat, ustawiajc dwie waciwoci typu Date w postaci acuchw -->
<bean id="testBean" class="ch02.sample9.StartEndDatesBean"<
<property name="startDate"<<value<10/09/1968</value<</property<
<property name="endDate"<<value<10/26/2004</value<</property<
</bean<

Postprocesor CustomPritorConfigurer moe rejestrowa jeden lub wiele niestandardowych


edytorw waciwoci (cho w prezentowanym przykadzie ograniczymy si do jednego,
CustomDatePritor). Twoje edytory (zaimplementowane z myl o innych typach) mog nie
wymaga adnych specjalnych zabiegw konfiguracyjnych. Z powyszego kodu konfiguracji wynika, e klasa CustomDatePritor, ktrej konstruktor pobiera na wejciu dwa argumenty, otrzyma obiekt klasy SimpleDateFormat reprezentujcy acuch formatu daty oraz
warto logiczn (typu boolean) okrelajc, czy acuchy puste powinny by traktowane
jak wartoci null.
Przedstawiony przykad ilustruje te wygodny sposb definiowania komponentu testowego
(w tym przypadku nazwanego testBean), ktry zawiera dwie waciwoci typu Date ustawiane za porednictwem wartoci acuchowych w ten sposb sprawdzamy, czy nasz
edytor waciwoci dziaa prawidowo.

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

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

Rozdzia 2. n Fabryka komponentw i kontekst aplikacji

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).

Po przeczytaniu tego rozdziau powiniene znacznie lepiej rozumie, co tak naprawd


oznaczaj takie pojcia jak odwracanie kontroli i wstrzykiwanie zalenoci oraz jak obie
koncepcje zostay urzeczywistnione w postaci fabryk komponentw i kontekstw aplikacji
Springa. Przeanalizowalimy i uylimy wikszoci podstawowych elementw funkcjonalnoci kontenera Springa. Poniewa wanie kontener IoC jest podstaw pozostaych mechanizmw Springa, dobre rozumienie sposobu jego funkcjonowania i technik konfiguracji
w poczeniu ze wiadomoci potencjau tego kontenera jest kluczem do efektywnego korzystania ze Springa.
Dowiedziae si midzy innymi:
n

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.

Jak kontener wspiera programist w stosowaniu podanej praktyki oddzielania


interfejsu od implementacji w kodzie aplikacji.

e postprocesory oferuj moliwo elastycznego dostosowywania zachowania


komponentw i kontenera (za pomoc odpowiednich plikw zewntrznych).

Jakie s podstawowe reguy odwracania kontroli i jak w poczeniu z fabryk


komponentw tworz doskonae narzdzie do budowy abstrakcji ponad operacjami
wymagajcymi dostpu do usug i zasobw.

e technika IoC wraz z odpowiednim kontenerem moe stanowi solidn podstaw


dla budowy aplikacji w oparciu o framework Spring bez koniecznoci tworzenia
cisych zwizkw pomidzy konstruowanym oprogramowaniem a samym kontenerem.

W nastpnym rozdziale skupimy si na bardziej zaawansowanych mechanizmach kontekstu


aplikacji i przedstawimy kilka zaawansowanych scenariuszy uycia kontenera.

D:\! AAA DZISIAJ\Spring Framework. Profesjonalne tworzenie oprogramowania w Javie\9 druk\r02.doc

133

You might also like