SlideShare a Scribd company logo
IDZ DO
         PRZYK£ADOWY ROZDZIA£

                           SPIS TREŒCI
                                         Spring. Zapiski
                                         programisty
           KATALOG KSI¥¯EK               Autorzy: Bruce A. Tate, Justin Gehtland
                                         T³umaczenie: Piotr Rajca
                      KATALOG ONLINE     ISBN: 83-246-0336-0
                                         Tytu³ orygina³u: Spring: A Developers Notebook
       ZAMÓW DRUKOWANY KATALOG           Format: B5, stron: 272


              TWÓJ KOSZYK
                                                                  Przyspiesz tworzenie aplikacji w Javie
                    DODAJ DO KOSZYKA         • Uproœæ okreœlanie zale¿noœci pomiêdzy klasami
                                             • Zastosuj narzêdzie Hibernate do usprawnienia komunikacji z bazami danych
                                             • Wykorzystaj mo¿liwoœci programowania aspektowego
         CENNIK I INFORMACJE             Technologia J2EE mia³a w za³o¿eniu byæ prosta i szybka w u¿ytkowaniu. Praktyka
                                         jednak okaza³a siê daleka od teorii. Mozolne tworzenie aplikacji wykorzystuj¹cych
                   ZAMÓW INFORMACJE      dziesi¹tki interfejsów po³¹czonych wzajemnymi zale¿noœciami, setki deskryptorów
                     O NOWOŒCIACH
                                         wdro¿enia oraz plików pomocniczych spowodowa³o, ¿e zaczêto poszukiwaæ rozwi¹zañ
                                         alternatywnych. Jednym z nich okaza³ siê framework Spring, zyskuj¹cy coraz wiêksz¹
                       ZAMÓW CENNIK      popularnoœæ wœród programistów Javy. Spring jest znacznie du¿o prostszy od wielu
                                         alternatywnych rozwi¹zañ J2EE, znacznie u³atwia testowanie aplikacji, i pozwala na
                                         usuwanie zale¿noœci z kodu oraz oddzielanie ich od serwera aplikacji. Spring umo¿liwia
                 CZYTELNIA               równie¿ wykorzystanie programowania aspektowego.
          FRAGMENTY KSI¥¯EK ONLINE       Ksi¹¿ka „Spring. Zapiski programisty” to praktyczny przewodnik po mo¿liwoœciach
                                         tego œrodowiska. Jeœli wolisz poznawaæ nowe zagadnienia w sposób praktyczny, a nie
                                         wertuj¹c setki stron zape³nionych teoretycznymi wywodami, to ta ksi¹¿ka jest w³aœnie
                                         dla Ciebie. Znajdziesz w niej omówienie zagadnieñ zwi¹zanych z samym Springiem,
                                         wspó³pracuj¹cymi z nim narzêdziami i sposobami wykorzystania ich w procesie
                                         tworzenia aplikacji J2EE — pocz¹wszy do graficznego interfejsu u¿ytkownika
                                         i interfejsu sieciowego, a skoñczywszy na dostêpie do relacyjnych baz danych.
                                             • Tworzenie klas z zastosowaniem zale¿noœci
                                             • Budowanie interfejsu u¿ytkownika
                                             • Integrowanie JSF z frameworkiem Spring
                                             • Dostêp do baz danych za pomoc¹ JDBC
                                             • Odwzorowanie baz danych na obiekty za pomoc¹ Hibernaete
Wydawnictwo Helion
                                             • Obs³uga i zabezpieczanie transakcji
ul. Chopina 6
                                             • Wysy³anie i odbieranie wiadomoœci e-mail
44-100 Gliwice
tel. (32)230-98-63                       Jeœli poszukujesz wydajniejszych metod tworzenia aplikacji J2EE, wykorzystaj
e-mail: helion@helion.pl                 mo¿liwoœci frameworka Spring. Dziêki tej ksi¹¿ce poznasz je wszystkie.
Spis treści


Przedmowa ............................................................................................ 5

Wstęp .................................................................................................... 9

Rozdział 1. Początki ............................................................................. 17
      Tworzenie dwóch klas przy wykorzystaniu zależności ....................... 18
      Stosowanie wstrzykiwania zależności ................................................ 23
      Automatyzacja przykładu ................................................................... 28
      Wstrzykiwanie zależności przy wykorzystaniu frameworka Spring ... 32
      Tworzenie testu ................................................................................... 35

Rozdział 2. Tworzenie interfejsu użytkownika ..................................... 41
      Konfiguracja Tomcata ......................................................................... 42
      Tworzenie widoku przy wykorzystaniu Web MVC ............................. 46
      Wzbogacanie aplikacji sieciowych ...................................................... 56
      Testowanie .......................................................................................... 65

Rozdział 3. Integracja innych klientów ................................................ 69
      Tworzenie interfejsu użytkownika w oparciu o framework Struts ....... 70
      Stosowanie JSF wraz z frameworkiem Spring ....................................... 83
      Integracja JSF z frameworkiem Spring ............................................... 92

Rozdział 4. Stosowanie JDBC ............................................................... 95
      Konfiguracja bazy danych i utworzenie schematu .............................. 96
      Stosowanie szablonów JDBC frameworka Spring .............................. 101
      Wydzielanie często używanego kodu ................................................ 108
      Stosowanie obiektów dostępowych .................................................... 110
      Wykonywanie testów przy użyciu szkieletu EasyMock .................... 116

                                                                                                                 3
Rozdział 5. Odwzorowania obiektowo-relacyjne ................................ 121
          Integracja frameworka iBATIS ..........................................................123
          Stosowanie frameworka Spring z JDO ...............................................134
          Stosowanie frameworków Hibernate oraz Spring ..............................142
          Testowanie ........................................................................................150

    Rozdział 6. Usługi i AOP ..................................................................... 151
          Tworzenie usługi ...............................................................................152
          Konfiguracja usługi ...........................................................................159
          Stosowanie automatycznych obiektów pośredniczących ....................164
          Porady operujące na wyjątkach .........................................................167
          Testowanie usługi przy wykorzystaniu obiektów zastępczych ..........170
          Testowanie usługi mającej efekty uboczne ........................................174

    Rozdział 7. Transakcje i bezpieczeństwo ........................................... 177
          Programowa obsługa transakcji ........................................................178
          Konfiguracja prostych transakcji .......................................................182
          Transakcje obejmujące kilka baz danych ..........................................184
          Zabezpieczenie serwletów aplikacji ...................................................190
          Zabezpieczanie metod aplikacji .........................................................200
          Tworzenie obiektu przechwytującego ułatwiającego testowanie ........206

    Rozdział 8. Obsługa wiadomości i praca zdalna ................................ 211
          Wysyłanie wiadomości poczty elektronicznej ....................................212
          Praca zdalna .....................................................................................216
          Stosowanie JMS .................................................................................219
          Testowanie aplikacji JMS ..................................................................224

    Rozdział 9. Tworzenie grubych klientów ............................................ 229
          Zaczynamy pracę ..............................................................................229
          Tworzenie widoku BikeNavigator ......................................................244
          Tworzenie formularzy edytora rowerów ...........................................249

    Skorowidz ......................................................................................... 259




4   Spis treści
ROZDZIAŁ 1.


                                                   Początki




W tym rozdziale:
   Tworzenie dwóch klas przy wykorzystaniu zależności
   Stosowanie wstrzykiwania zależności
   Automatyzacja przykładu
   Wstrzykiwanie zależności przy wykorzystaniu frameworka Spring
   Tworzenie testu
W weekendy z wielkim zapałem oddaję się sportom ekstremalnym. We-
dług standardów właściwych dla osób przeciętnych, robiłem na rowerze
górskim naprawdę zwariowane rzeczy, a oprócz tego uwielbiam kaja-
karstwo górskie. Tylko raz znalazłem się w poważnych kłopotach. Spływa-
łem na rzece o nazwie Piedra, na której byłem po raz pierwszy, w nowym
sprzęcie i z głową naładowaną nowymi technikami. W kajakarstwie
górskim przeżycie zależy od zachowania prostoty i szybkości, a ja byłem
niepewny i wolny. Zamiast atakować rzekę, to ona zaatakowała mnie;
przepłynąłem przez trzy bystrza klasy IV i naprawdę miałem szczęście,
że wyszedłem z tego bez żadnych obrażeń.
Szybkość i prostota ma równie duże znaczenie w przypadku tworzenia
oprogramowania. Spring Framework daje mi jedno i drugie. Kupiłeś tę
książkę, więc zapewne zgadzasz się z tym stwierdzeniem. Spring, choć
jest prosty, ma bardzo duże możliwości. Ogromne. Spring pozwoli Ci na pi-
sanie aplikacji o architekturze warstwowej, w której poszczególne warstwy


                                                                            17
będę wyraźnie od siebie oddzielone. Spring sprawia, że będziesz mógł
                        testować tworzony kod w tak prosty i przejrzysty sposób, o jakim wcze-
                        śniej nawet nie mogłeś marzyć. W niniejszym rozdziale stworzysz pro-
                        stą aplikację, zautomatyzujesz proces jej kompilacji i przystosujesz ją do
                        korzystania z frameworka Spring.


Spring jest najpopu-
larniejszym produk-
                        Tworzenie dwóch klas
tem z nowej grupy
tak zwanych
                        przy wykorzystaniu zależności
lekkich kontenerów.
                        Wielu nauczycieli i konsultantów pisze o zależnościach jako o czymś, co
Jeśli uwzględnimy
wszystkie wchodzą-      można by porównać do majonezu zbyt długo pozostawionego na słońcu.
ce w jego skład mo-     Jednak jeśli tworzona aplikacja ma robić cokolwiek interesującego, to za-
duły, to się okaże,
że Spring nie jest aż
                        leżności muszą się w niej pojawić. Cała sztuka polega na tym, by ziden-
taki „lekki”, jednak    tyfikować ważne zależności i obsłużyć je w odpowiedni sposób. Sposób,
w tym przypadku         w jaki rozwiążesz zależności, będzie mieć znaczący wpływ na łatwość
określenie to odnosi
się do tego wszyst-     utrzymania aplikacji, jej rozbudowy oraz testowania. Podczas lektury
kiego, co zazwyczaj     niniejszej książki napiszesz system rezerwacji rowerów górskich. Sklep
trzeba dodawać do
                        sportowy mógłby korzystać z takiego systemu do rezerwacji i wypożyczania
kodu umieszczanego
i wykonywanego          rowerów. Zaczniemy od najprostszych rozwiązań, w których wszystkie
w kontenerze.           zależności będą określone na stałe w kodzie; w ten sposób będziemy mogli
                        się upewnić, że używana infrastruktura działa poprawnie. Następnie roz-
                        luźnimy powiązania za pomocą frameworka Spring i stopniowo będzie-
                        my dodawać do naszej aplikacji trwałość, warstwę prezentacji sieciowej,
                        deklaratywne transakcje i kilka innych usług.
                        Dla mnie tworzenie przy wykorzystaniu frameworka Spring ma charakter
                        iteracyjny. Najbliższych kilka ćwiczeń jest poświęconych powolnemu
                        przygotowywaniu infrastruktury. W pierwszym upewnimy się, że dys-
                        ponujemy poprawnie skonfigurowanym oraz działającym środowiskiem
                        Javy i zaczniemy tworzyć podstawowy model aplikacji. Każdy z kilku
                        pierwszych przykładów jest poświęcony niewielkiemu fragmentowi śro-
                        dowiska, co ułatwi nam rozwiązywanie ewentualnych problemów, gdyby
                        jakieś się pojawiły.




18                      Rozdział 1: Początki
Jak to osiągnąć?
Zaczniemy od dwóch klas umieszczonych w jednym katalogu. Pierwsza
z nich będzie reprezentować rower górski, a druga rejestr, w którym będą
przechowywane informacje o wszystkich rowerach. Tę drugą klasę na-
zwiemy fasadą. Informacje o posiadanych rowerach będą podawane
w konstruktorze fasady, a następnie wyświetlane przy wykorzystaniu
trzeciej, bardzo prostej klasy.
Klasa Bike, reprezentująca rower, została przedstawiona na listingu 1.1.

Listing 1.1. Bike.java
    public class Bike {
       private String manufacturer;
       private String model;
       private int frame;
       private String serialNo;
       private double weight;
       private String status;

        public Bike() {}

        public Bike(String manufacturer, String model, int frame, String
        serialNo, double weight, String status) {
           this.manufacturer = manufacturer;
           this.model = model;
           this.frame = frame;
           this.serialNo = serialNo;
           this.weight = weight;
           this.status = status;
        }

        public String toString() {
           return "Rower : " +
                 "producent -- " + manufacturer +
                 "n: model -- " + model +
                 "n: rama -- " + frame +
                 "n: numer seryjny -- " + serialNo +
                 "n: waga -- " + weight +
                 "n: status -- " + status +
                 ".n"; }

        public String getManufacturer() { return manufacturer; }

        public void setManufacturer(String manufacturer) {
           this.manufacturer = manufacturer;
        }




                                Tworzenie dwóch klas przy wykorzystaniu zależności   19
public String getModel() { return model; }

             public void setModel(String model) { this.model = model; }

             public int getFrame() { return frame; }

             public void setFrame(int frame) { this.frame = frame; }

             public String getSerialNo() { return serialNo; }

             public void setSerialNo(String serialNo) { this.serialNo = serialNo; }

             public double getWeight() { return weight; }

             public void setWeight(double weight) { this.weight = weight; }

             public String getStatus() { return status; }

             public void setStatus(String status) { this.status = status; }
         }


     Listing 1.2 przedstawia fasadę.

     Listing 1.2. RentABike.java
         import java.util.Iterator;
         import java.util.List;
         import java.util.ArrayList;

         public class RentABike {

             private String storeName;
             final List bikes = new ArrayList();

             public RentABike(String storeName) {
                this.storeName = storeName;
                bikes.add(new Bike("Shimano", "Roadmaster", 20, "11111", 15,
                      "Dobry"));
                bikes.add(new Bike("Cannondale", "F2000 XTR", 18, "22222",12,
                      "Doskonały"));
                bikes.add(new Bike("Trek","6000", 19, "33333", 12.4,
                      "Dobry"));
             }

             public String toString() { return "RentABike: " + storeName; }

             public List getBikes() { return bikes; }

             public Bike getBike(String serialNo) {
                Iterator iter = bikes.iterator();
                while(iter.hasNext()) {
                   Bike bike = (Bike)iter.next();
                   if(serialNo.equals(bike.getSerialNo())) return bike;


20   Rozdział 1: Początki
}
            return null;
        }
    }

I w końcu kod zamieszczony na listingu 1.3 przedstawia widok.

Listing 1.3. CommandLineView.java
    import java.util.Iterator;

    public class CommandLineView {
       private RentABike rentaBike;                                                      Klasa RentABike
       public CommandLineView() {rentaBike = new RentABike("Rowery Bruce'a");}
                                                                                         jest zależnością.
                                                                                         W przypadku sto-
        public void printAllBikes() {
                                                                                         sowania takiego
           System.out.println(rentaBike.toString());
           Iterator iter = rentaBike.getBikes().iterator();                              stylu programowa-
           while(iter.hasNext()) {                                                       nia zależności są
              Bike bike = (Bike)iter.next();                                             podawane na stałe,
              System.out.println(bike.toString());                                       co zwiększa stopień
           }                                                                             wzajemnego powią-
        }                                                                                zania fasady i wido-
        public static void main(String[] args) {                                         ku. Framework
           CommandLineView clv = new CommandLineView();                                  Spring pomoże
           clv.printAllBikes();                                                          nam wyeliminować
        }                                                                                zależności
    }                                                                                    takiego typu.

Teraz możesz już skompilować aplikację, używając następującego polecenia:
    C:PozyczRowerAppsrc javac -d ..out *.java

Katalog wynikowy będzie teraz zawierać skompilowane pliki klas:
    Katalog: C:PozyczRowerAppout

    2005-12-27    08:17    <DIR>            .
    2005-12-27    08:17    <DIR>            ..
    2005-12-27    08:17               1 753 Bike.class
    2005-12-27    08:17               1 442 RentABike.class
    2005-12-27    08:17                 937 CommandLineView.class

Aplikację możesz uruchomić w następujący sposób:
    C:PozyczRowerAppout> java CommandLineView

    RentABike: Rowery Bruce'a
    Rower : producent -- Shimano
    : model -- Roadmaster
    : rama -- 20
    : numer seryjny -- 11111
    : waga -- 15.0
    : status -- Dobry.



                                    Tworzenie dwóch klas przy wykorzystaniu zależności                     21
Rower : producent -- Cannondale
                          : model -- F2000 XTR
                          : rama -- 18
                          : numer seryjny -- 22222
                          : waga -- 12.0
                          : status -- Doskonały.

                          Rower : producent -- Trek
                          : model -- 6000
                          : rama -- 19
                          : numer seryjny -- 33333
                          : waga -- 12.4
                          : status -- Dobry.


                      Jak to działa?
                      Nic dobrego. Nasz aktualny projekt jest bardzo prosty, lecz jednocześnie
                      wszystkie powiązania są określone na stałe. Od razu można wskazać kilka
                      wad takiego rozwiązania:
                       • Warstwa fasady (RentABike) w statyczny sposób tworzy rowery do-
Podstawowy               stępne w sklepie, a zatem, za każdym razem, gdy pojawi się jakiś
wzorzec projektowy       nowy rower (ech!), bądź też gdy użytkownik „skasuje” jakiś rower
stosowany we
frameworku Spring        (co za pech!), konieczne będzie wprowadzanie odpowiednich zmian
oraz innych lekkich      w kodzie.
kontenerach, bazuje
na zmniejszeniu        • Także przetestowanie modelu będzie kłopotliwe, gdyż zbiór rowerów
stopnia powiązań
                         jest stały i niezmienny.
pomiędzy
zależnościami.         • Interfejs użytkownika oraz fasada są ze sobą ściśle powiązane. Można
                         wskazać podaną na stałe zależność pomiędzy warstwą fasady i in-
                         terfejsem użytkownika.
                       • Kod źródłowy nie jest w żaden sposób zorganizowany, a proces kom-
                         pilacji aplikacji nie jest zautomatyzowany.
                      Jednak teraz chcemy wprowadzić pewne ułatwienia, by poprawić dzia-
                      łanie środowiska Javy, tworząc jednocześnie podwaliny naszej aplikacji.
                      W następnym przykładzie rozdzielimy poszczególne warstwy aplikacji
                      i zautomatyzujemy proces jej kompilacji.




22                    Rozdział 1: Początki
A co z…
… przygotowaniem tego całego burrito raz a dobrze? Możesz zdecydo-
wać, by jednocześnie zainstalować Spring, Hiberanate, Javę, Ant oraz
JUtil. Jednak z własnego doświadczenia mogę stwierdzić, że zajmując się
kolejno każdym zagadnieniem z osobna, w rzeczywistości oszczędzamy
czas; zwłaszcza jeśli tworzymy podstawy środowiska pracy. Kiedy wszyst-
kie narzędzia zostaną już zainstalowane i będą działać poprawnie, będziesz
mógł połączyć kilka czynności.


Stosowanie wstrzykiwania zależności
Kiedy zaczynam tworzyć aplikację, zazwyczaj jej poszczególne elementy
są ze sobą ściśle powiązane. Nie ma w tym nic złego. W każdej chwili
mogę to zmienić w późniejszych etapach pracy. W niniejszym przykła-
dzie zmienię strukturę aplikacji w taki sposób, aby współpracowała
z frameworkiem Spring w przypadku, gdy zostanie on wykorzystany.
W tym celu dodam do warstwy fasady interfejs, aby mogła ona imple-
mentować kilka różnych strategii.                                               Wiele osób, gdy po
                                                                                raz pierwszy styka
Pierwszym krokiem podczas poznawania frameworka Spring jest po-                 się z wstrzykiwa-
                                                                                niem zależności,
znanie wzorca wstrzykiwania zależności (ang. dependency injection).
                                                                                dziwi się: „O co tyle
Nie jest on skomplikowany, choć ma kluczowe znaczenie. Jest on na tyle          hałasu?”. Jednak
odmienny od standardowo przyjętego sposobu kodowania, że zapewne                kiedy zaczną uży-
                                                                                wać tej techniki,
będziesz chciał zanotować sobie skrócone informacje na jego temat.              po pewnym czasie
                                                                                zrozumieją, iż ta
Rysunek 1.1 przedstawia klienta i serwer przygotowane do wykorzysta-
                                                                                prosta zmiana
nia techniki wstrzykiwania zależności. Klient używa innej klasy, którą          może w ogromnym
będziemy nazywali usługą. Klient posiada właściwość, a w niej można             stopniu poprawić
zapisać referencję do usługi. Usługa jest z kolei reprezentowana przez          tworzony kod
                                                                                i ułatwić utrzymanie
interfejs, co sprawia, że klient nie zna jej faktycznej implementacji.          aplikacji.
Niemniej jednak taki kod nie cechuje się niskim stopniem powiązań —
wciąż w jakiś sposób musimy utworzyć usługę. Dzięki wstrzykiwaniu
zależności jakieś dodatkowe narzędzie, nazywane asemblerem lub kon-
tenerem, odpowiada za utworzenie zarówno klienta, jak i usługi, a na-
stępnie określa wartość właściwości aService (będącej referencją do
obiektu typu Service stanowiącego implementację usługi), spełniając tym
samym wymagane zależności.

                                          Stosowanie wstrzykiwania zależności                      23
Rysunek 1.1. Klient używa usługi reprezentowanej przez interfejs

     Prawdopodobnie już zdarzało Ci się stosować taki sposób kodowania.
     Jednak dopiero teraz, kiedy wykorzystamy framework, który w spójny spo-
     sób używa tego modelu programowego w obrębie całej aplikacji, przeko-
     namy się, jak duże możliwości on zapewnia. Kod składający się z luźno
     powiązanych komponentów jest znacznie prostszy do testowania, utrzy-
     mania i zrozumienia.

     Jak to zrobić?
     Aby stosować ten model projektowy, wcale nie trzeba korzystać z lek-
     kich kontenerów. W celu rozdzielenia elementów programu przy wyko-
     rzystaniu wstrzykiwania zależności należy wykonać trzy czynności:
     1.   Stworzyć interfejs, który będzie reprezentować usługę.
     2.   Dodać do klienta właściwość odwołującą się do usługi.
     3.   Przy wykorzystaniu dodatkowego frameworka lub własnego kodu
          stworzyć usługę i przypisać odpowiednią wartość właściwości klienta.
     Pierwszym krokiem jest wydzielenie interfejsu. Teraz zmienimy nazwę
     pliku, definicji klasy oraz konstruktora RentABike na ArrayListRentABike
     (listing 1.4) i stworzymy interfejs (listing 1.5).

     Listing 1.4. ArrayListRentABike.java (wcześniej RentABike.java)
          import java.util.List;
          import java.util.ArrayList;
          import java.util.Iterator;

          public class ArrayListRentABike implements RentABike {
             private String storeName;
             final List bikes = new ArrayList();

             public ArrayListRentABike(String storeName) {
                this.storeName = storeName;
                bikes.add(new Bike("Shimano", "Roadmaster", 20, "11111", 15,


24   Rozdział 1: Początki
"Dobry"));
            bikes.add(new Bike("Cannondale", "F2000 XTR", 18, "22222",12,
                  "Doskonały"));
            bikes.add(new Bike("Trek","6000", 19, "33333", 12.4,
                  "Dobry"));
        }

        public ArrayListRentABike() {
           this("Rowery Bruce'a");
        }

        public void setStoreName(String storeName) { this.storeName =
        storeName; }
        public String getStoreName() { return this.storeName; }

        public String toString() { return "RentABike: " + storeName; }

        public List getBikes() { return bikes; }

        public Bike getBike(String serialNo) {
           Iterator iter = bikes.iterator();
           while(iter.hasNext()) {
              Bike bike = (Bike)iter.next();
              if(serialNo.equals(bike.getSerialNo())) return bike;
           }
           return null;
        }
    }


Listing 1.5. RentABike.java
    import java.util.*;

    public interface RentABike {
       List getBikes();
       Bike getBike(String serialNo);
    }

Kolejnym elementem programu jest widok, przedstawiony na listingu                    Teraz będziemy
1.6. Warto zauważyć, że wydzieliliśmy metody, które wyświetlają in-                  mogli zobaczyć
                                                                                     usługę RentABike
formacje o rowerze w wierszu poleceń. Dodaliśmy także do widoku wła-                 udostępnioną
ściwość, w której można zapisać obiekt typu RentABike.                               w formie właściwo-
                                                                                     ści. Nieco później jej
Listing 1.6. CommandLineView.java                                                    wartość zostanie
                                                                                     określona przez
    import java.util.*;                                                              framework Spring.

    public class CommandLineView {
       private RentABike rentaBike;
       public CommandLineView() {}

        public void setRentaBike(RentABike rentaBike) {


                                               Stosowanie wstrzykiwania zależności                       25
this.rentaBike = rentaBike;
                                }

                                public RentABike getRentaBike() { return this.rentaBike; }

                                public void printAllBikes() {
                                   System.out.println(rentaBike.toString());
                                   Iterator iter = rentaBike.getBikes().iterator();
                                   while(iter.hasNext()) {
                                      Bike bike = (Bike)iter.next();
                                      System.out.println(bike.toString());
                                   }
                                }
                            }

Tutaj możemy            Ostatnim elementem aplikacji jest asembler, który tworzy wszystkie obiekty
zaobserwować            i określa wartość właściwości (listing 1.7).
działanie wstrzyki-
wania zależności.
Dodatkowy kod,
                        Listing 1.7. RentABikeAssembler.java
w tym przypadku             public class RentABikeAssembler {
napisany przez nas,            public static final void main(String[] args) {
tworzy oba obiekty                CommandLineView clv = new CommandLineView();
i wstrzykuje referen-             RentABike rentaBike = new ArrayListRentABike("Rowery Bruce'a");
cję typu RentABike                clv.setRentABike(rentaBike);
do obiektu widoku.                clv.printAllBikes();
                               }
                            }

                        Teraz można skompilować aplikację, wykonując następujące polecenie:
                            C:PozyczRowerAppsrc> javac -d ..out *.java

                        Katalog wynikowy będzie zawierać następujące, skompilowane pliki klas:
                            Katalog: C:PozyczRowerAppout
                            2005-12-31    15:28    <DIR>               .
                            2005-12-31    15:28    <DIR>               ..
                            2006-01-02    15:02                1 737   Bike.class
                            2006-01-02    15:02                1 477   ArrayListRentABike.class
                            2006-01-02    15:02                  186   RentABike.class
                            2006-01-02    14:58                  944   CommandLineView.class
                            2006-01-02    14:58                  496   RentABikeAssembler.class

                        Aplikację można uruchomić w następujący sposób:
                            C:PozyczRowerAppout>java RentABikeAssembler
                            RentABike: Rowery Bruce'a
                            Rower : producent -- Shimano
                            : model -- Roadmaster
                            : rama -- 20
                            : numer seryjny -- 11111



26                      Rozdział 1: Początki
: waga -- 15.0
   : status -- Dobry.

   Rower : producent -- Cannondale
   : model -- F2000 XTR
   : rama -- 18
   : numer seryjny -- 22222
   : waga -- 12.0
   : status -- Doskonały.

   Rower : producent -- Trek
   : model -- 6000
   : rama -- 19
   : numer seryjny -- 33333
   : waga -- 12.4
   : status -- Dobry.


Jak to działa?
Właśnie zobaczyłeś przykład wstrzykiwania zależności poza środowi-
skiem lekkiego kontenera. Choć środowiska twórców i użytkowników
lekkich kontenerów robią wiele hałasu w związku z wstrzykiwaniem
zależności, to jednak pomysły leżące u podstaw tego rozwiązania są cał-
kiem proste. Pisząc programy, należy używać interfejsów, a zależności
nie określać samemu, lecz przy wykorzystaniu dodatkowego narzędzia.
W naszych przykładach, asemblery zastąpimy w końcu frameworkiem
Spring. Kiedy to się stanie, framework będzie samodzielnie wywoływać
konstruktory używanych obiektów i określać występujące pomiędzy nimi
zależności. Niemniej jednak na razie musimy poświęcić tej wersji apli-
kacji nieco więcej uwagi.

A co z…
… lokalizatorami usług lub obiektami fabrykującymi? Oczywiście wstrzy-
kiwanie zależności nie jest jedynym sposobem rozwiązywania zależności
występujących pomiędzy obiektami. W rzeczywistości nie jest to jedyny
dobry sposób rozwiązywania tego problemu. Osoby korzystające z tech-
nologii J2EE wykorzystują zazwyczaj lokalizatory usług (ang. service
locators). Używając tego wzorca (przedstawionego na rysunku 1.2), można
przedstawić zależność w formie interfejsu, zarejestrować ją w słowniku,
a następnie odszukać przy wykorzystaniu dodatkowej klasy pomocniczej
nazywanej lokalizatorem (ang. locator). Nie jest to wcale złe rozwiązanie.

                                          Stosowanie wstrzykiwania zależności   27
Rysunek 1.2. Aplikacje J2EE zarządzają zależnościami przy wykorzystaniu
     lokalizatorów usług

     Strategia wstrzykiwania zależności pozwala na zastosowanie spójnego
     rozwiązania i całkowite oddzielenie zależności od tworzonej aplikacji.
     W dalszej części rozdziału przekonasz się, w jaki sposób rozwiązanie to
     może pomóc w testowaniu aplikacji i tworzeniu programów zapewniają-
     cych dużą łatwość utrzymania i konfiguracji.
     W rzeczywistości wcześniejsze lekkie kontenery, takie jak Avalon, wy-
     korzystywały właśnie to rozwiązanie. Większość nowoczesnych konte-
     nerów udostępnia mechanizmy służące do wyszukiwania zależności, choć
     zazwyczaj preferowane są inne sposoby ich rozwiązywania.


     Automatyzacja przykładu
     Najwyższy czas na małe porządki. Aby móc pójść dalej, konieczne jest
     zastosowanie automatyzacji. Prawdopodobnie używasz już programu
     Ant. Stanowi on standaryzowany sposób organizacji wszystkich zadań,
     jakie należy wykonać w celu skompilowania i przygotowania aplikacji.
     Jeśli jeszcze nie używasz tego programu, to będziesz musiał zacząć.
     Ant stał się wszechobecny. Aby móc posługiwać się narzędziami pro-
     gramistycznymi języka Java, konieczne będzie postanie używanego przez
     nie „języka”. Nie mamy zamiaru zamieszczać w tym rozdziale uzasad-
     nienia, dlaczego warto korzystać z programu Ant, gdyż zapewnie i tak
     już wiele na ten temat czytałeś.




28   Rozdział 1: Początki
Jak to zrobić?
Nie ma potrzeby pobierania pakietu instalacyjnego programu Ant —
można wykorzystać ten, który jest dostępny wraz z frameworkiem Spring
(http://springframework.org/). W celu wykonania wszystkich przykładów
zamieszczonych w tej książce będziesz potrzebował frameworka Spring
w wersji 1.1 lub późniejszej. Podczas jego instalacji należy postępować
zgodnie z zaleceniami dotyczącymi używanego systemu operacyjnego.
Kolejnym krokiem po zainstalowaniu frameworka Spring będzie zorga-
nizowanie takiej struktury katalogów, która będzie wygodna zarówno dla
frameworka Spring, jak i dla tworzonej aplikacji. Zalecamy zastosowa-
nie takiej samej organizacji, jaka została użyta w przykładowej aplikacji
dostarczanej wraz z frameworkiem Spring, dzięki czemu zyskamy możli-
wość przeanalizowania gotowego, działającego przykładu. Poniżej przed-
stawiliśmy listę katalogów, z których będziemy korzystać:
src
       W tym katalogu przechowywane są wszystkie kody źródłowe apli-
       kacji. Jak zwykle struktura podkatalogów umieszczonych wewnątrz
       tego katalogu powinna odpowiadać strukturze pakietów.
test
       W tym katalogu przechowywane są wszystkie testy modułów. Więcej
       informacji dotyczących JUnit można znaleźć w ostatnim ćwiczeniu
       zamieszczonym pod koniec tego rozdziału.
db
       W tym katalogu umieszczane są wszelkie zasoby związane z bazami
       danych — skrypty, konfiguracje oraz kody. Niektóre z nich będą pli-
       kami konfiguracyjnymi, inne plikami pomagającymi stworzyć bazę
       danych o odpowiedniej strukturze, a jeszcze inne pozwolą na zapi-
       sanie w bazie informacji testowych. Jeśli nasza aplikacja ma współ-
       pracować z kilkoma różnymi bazami danych, to dla każdej z tych baz
       w katalogu db zostanie utworzony odrębny podkatalog.




                                                     Automatyzacja przykładu   29
war
                            Plik war jest typową jednostką wdrażania aplikacji sieciowych. Jeśli
                            używasz kontenera J2EE lub kontenera serwletów, takiego jak Tomcat,
                            to w tym katalogu będzie umieszczany plik konfiguracyjny web.xml.
                            W tym katalogu będą umieszczane także pliki konfiguracyjne uży-
                            wane przez framework Spring. Informacje o plikach konfiguracyjnych
                            Springa zostały podane w ćwiczeniach zamieszczonych w dalszej
                            części książki.
                         Na początek rozmieść pliki wchodzące w skład naszej aplikacji w nastę-
                         pujący sposób:
                          • Plik RentABike.java — w katalogu src, w podkatalogach odpowia-
                            dających strukturze pakietów.
                          • Plik ArrayListRentABike.java — w katalogu src wraz z plikiem
                            RentABike.java.
                          • Plik Bike.java — w katalogu src wraz z plikiem RentABike.java.
                          • Plik CommandLineView.java — w katalogu src wraz z plikiem
                            RentABike.java.
                         W końcu będzie Ci potrzebny skrypt programu Ant, który należy umie-
                         ścić w głównym katalogu projektu. Listing 1.8 przedstawia skrypt od któ-
                         rego zaczniemy:

                         Listing 1.8. build.xml
To właśnie w tym             <?xml version="1.0"?>
pliku przekażesz             <project name="RentABike" default="compile" basedir=".">
programowi Ant
informacje dotyczą-              <property   name="src.dir" value="src"/>
ce położenia plików              <property   name="test.dir" value="test"/>
klas wchodzących                 <property   name="war.dir" value="war"/>
                                 <property   name="class.dir" value="${war.dir}/WEB-INF/classes"/>
w skład aplikacji.
Można je dołączyć
                                 <target name="init">
do pliku war aplikacji
                                    <mkdir dir="${class.dir}"/>
lub wskazać bezpo-               </target>
średnio ich wersje
instalacyjne i poin-             <target name="compile" depends="init"
formować użyt-                      description="Compiles all source code.">
kowników, jakie                     <javac srcdir="${src.dir}" destdir="${class.dir}"/>
pliki muszą wdrożyć.             </target>



30                       Rozdział 1: Początki
<target name="clean" description="Erases contents of classes dir">
         <delete dir="${class.dir}"/>
      </target>

   </project>

W celu wykonania powyższego skryptu programu Ant należy przejść do
katalogu o nazwie C:PozyczRowerApp i wydać następujące polecenie:              Właśnie to nazy-
                                                                                wam automatyza-
   C:PozyczRowerApp>ant                                                        cją. Ograniczyliśmy
   Buildfile: build.xml
                                                                                całkowitą liczbę
   init:                                                                        klawiszy, jakie nale-
       [mkdir] Created dir: C:PozyczRowerAppwarWEB-INFclasses               ży nacisnąć w celu
                                                                                skompilowania
   compile:                                                                     i przygotowania
       [javac] Compiling 5 source files to C:PozyczRowerAppwar               aplikacji — w tym
       WEB-INFclasses
                                                                                momencie cały
   BUILD SUCCESSFUL                                                             proces wymaga
   Total time: 2 seconds                                                        naciśnięcia dokładnie
                                                                                czterech klawiszy.

Jak to działa?
Program Ant przygotował aplikację w jednym, zautomatyzowanym kroku.
Jak na razie nie jest to co prawda wielkim ułatwieniem, jednak znacze-
nie tej automatyzacji będzie stopniowo rosło, wraz ze wzrostem stopnia
złożoności poszczególnych czynności wykonywanych w ramach kom-
pilacji i przygotowywania aplikacji. Później będziesz chciał, by system
samoczynnie wykonywał testy modułów, dodawał operacje związane                  Szczerze mówiąc,
                                                                                budujemy tę aplika-
z prekompilacją, takie jak wzbogacenie kodów bajtowych przez JDO (patrz         cję w zintegrowa-
rozdział 5.) lub kopiował pliki konfiguracyjne w odpowiednie miejsca.           nym środowisku
                                                                                programistycznym
Można także wykonywać zadania specjalne w celu zainicjowania bazy
                                                                                o nazwie IDEA,
danych lub wdrożenia pliku war na serwer aplikacji.                             stworzonym przez
                                                                                firmę JetBrains.
                                                                                Według nas dyspo-
A co z…                                                                         nuje ono najlepszymi
                                                                                dostępnymi możli-
… faktem, że niektóre zintegrowane środowiska programistyczne w ogóle
                                                                                wościami refakto-
nie muszą korzystać z programu Ant? Jeśli chcesz używać takich śro-             ringu. Ale się nie
dowisk programistycznych i nie przejmować się programem Ant, to bę-             przejmuj — każdą
                                                                                prezentowaną wer-
dziesz musiał upewnić się, że:                                                  sję aplikacji testo-
                                                                                waliśmy także
 • Kod będzie rozmieszczony w katalogach o takiej samej strukturze              przy wykorzystaniu
   jak zastosowana przez nas, by nie pojawiły się żadne problemy z pa-          skryptów
   kietami.                                                                     programu Ant.



                                                      Automatyzacja przykładu                      31
• Zintegrowane środowisko programistyczne będzie miało dostęp do
        wszystkich plików .jar, z których będziemy korzystać.
      • W dalszych rozdziałach będziesz musiał znaleźć sposób wdrażania
        i uruchamiania aplikacji sieciowej, oraz wykonywania testów JUnit.
     Od tej chwili aż do końca książki będziemy informować, kiedy konieczne
     będzie dodanie nowego katalogu, wykonanie aplikacji lub udostępnienie
     nowej biblioteki. Nie będziemy jednak opisywać, jak należy to zrobić, za-
     kładając, że będziesz w stanie wykorzystać do tego celu możliwości używa-
     nego środowiska programistycznego lub będziesz wiedzieć, jak to uczy-
     nić bezpośrednio w skrypcie programu Ant.


     Wstrzykiwanie zależności
     przy wykorzystaniu frameworka Spring
     Już niemal przygotowaliśmy naszą aplikację do zastosowania frame-
     worka Spring. Czas go pobrać i użyć. W tym ćwiczeniu zastąpimy obiekt
     RentABikeAssembler frameworkiem Spring.

     Kiedy zacząłem używać Springa zamiast J2EE, moje życie się odmieniło.
     Stałem się znacznie bardziej produktywny. Okazało się, że pisanie kodu
     łatwiej stało się dla mnie łatwiejsze, a tworzony przeze mnie kod jest
     łatwiejszy do zrozumienia dla moich klientów. Z kolei uproszczenie kodu
     niejednokrotnie pozwalało na jego szybsze działanie. Poza tym wprowa-
     dzanie jakichkolwiek zmian w kodzie stało się nieporównanie łatwiejsze.
     W rzeczywistości napisałem książkę o znaczeniu i zaletach lekkich fra-
     meworków takich jak Spring; nosi ona nazwę Better, Faster, Lighter Java
     i została wydana przez wydawnictwo O’Reilly.

     Jak to zrobić?
     W pierwszej kolejności należy pobrać pakiet instalacyjny frameworka
     Spring. Można go znaleźć na witrynie http://springframework.org/. Stamtąd
     należy przejść na witrynę Sourceforge, na której można znaleźć wersję
     frameworka dostosowaną do używanego systemu operacyjnego (podczas
     pisania niniejszej książki używaliśmy wersji Spring 1.1). Następnie trzeba


32   Rozdział 1: Początki
dodać do projektu nowy katalog — warWEB-INFlib — i umieścić w nim
biblioteki frameworka Spring (całą zawartość katalogu dist dostępnego
w pakiecie instalacyjnym frameworka Spring).
Modyfikacja poprawnie zaprojektowanej aplikacji bazującej na zwyczaj-
nych, starych obiektach Javy — w skrócie POJO (ang. Plain Old Java
Objects) — i przystosowanie jej do korzystania z frameworka Spring nie
przysparza najmniejszych problemów. Wszystko sprowadza się do wy-
konania poniższych czynności:
 • Zmodyfikowania kodu tak, aby korzystał ze wstrzykiwania zależności.
   Obiekty modelu są komponentami, a usługi — aspektami. Zazwy-
   czaj jednak będziesz używał jedynie komponentów.
 • Usunięcia kodu, który tworzy obiekty i rozwiązuje zależności.
 • Napisania pliku konfiguracyjnego opisującego używane komponenty
   i aspekty.
 • Odwołania się do napisanego kodu za pośrednictwem frameworka
   Spring.
Ponieważ poszczególne elementy naszej aplikacji są już przygotowane
do wykorzystania wstrzykiwania zależności, zatem zastosowanie fra-
meworka Spring będzie łatwym ćwiczeniem. Po prostu zastąpimy nasz
asembler wersją korzystającą z frameworka i stworzymy plik konfigu-
racyjny, który zostanie umieszczony w katalogu warWEB-INF.
Plik konfiguracyjny został przedstawiony na listingu 1.9.

Listing 1.9. RentABike-context.xml
    <?xml version="1.0"?>
    <!DOCTYPE beans PUBLIC"-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">

    <beans>
       <bean id="rentaBike" class="com.springbook.ArrayListRentABike">
          <property name="storeName"><value>Rowery Bruce'a</value></property>
       </bean>

        <bean id="commandLineView" class="com.springbook.CommandLineView">
           <property name="rentaBike"><ref bean="rentaBike"/></property>
        </bean>

    </beans>


                      Wstrzykiwanie zależności przy wykorzystaniu frameworka Spring   33
Aby uruchomić skrypt przygotowujący aplikację, należy przejść do ka-
     talogu PozyczRowerApp i wydać następujące polecenie:
         C:PozyczRowerAppant
         Buildfile: build.xml

         init:
             [mkdir] Created dir: C:PozyczRowerAppwarWEB-INFclasses

         compile:
             [javac] Compiling 5 source files to C:PozyczRowerAppwarWEB-
         INFclasses

         BUILD SUCCESSFUL
         Total time: 2 seconds

     Na listingu 1.10 został przedstawiony nowy asembler, który zastąpił
     wcześniejszą klasę RentABikeAssembler.

     Listing 1.10. RentABikeAssembler.java
         package com.springbook;

         import org.springframework.context.support.ClassPathXmlApplicationContext;

         public class RentABikeAssembler {
            public static final void main(String[] args) {
               ClassPathXmlApplicationContext ctx = new
               ClassPathXmlApplicationContext("RentABike-context.xml");
               CommandLineView clv =
               (CommandLineView)ctx.getBean("commandLineView");
               clv.printAllBikes();
            }
         }


     Jak to działa?
     Być może drapiesz się po głowie i zastanawiasz, co w tym wszystkim
     jest takiego niezwykłego. Jednak te niewielkie zmiany architektury będą
     miały znaczący wpływ na cykl życia aplikacji. Korzyści wynikające z ich
     wprowadzenia można zauważyć niemal od razu. Nie będę Cię zanudzać
     i opisywać ich dokładnie. Zamiast tego napiszę o tym, co się dzieje w ukry-
     ciu — w sposób niezauważalny dla programisty.




34   Rozdział 1: Początki
A co z…
… Pico, Hive Mind oraz Avalonem? To wszystko są lekkie kontenery.
Każdy z nich ma swoje silne i słabe punkty. Ani Avalon, ani Hive Mind
nie uzyskały na tyle dużej masy krytycznej, abyś chciał myśleć o ich
zastosowaniu, zwłaszcza jeśli chcesz używać usług, które są w stanie
współdziałać ze sobą. Obecnie największe udziały w rynku mają frame-
worki Spring oraz Pico. Programiści poszukujący samodzielnego konte-
nera zazwyczaj decydują się na wykorzystanie Pico, jednak Spring po-
siada najbardziej rozbudowane i kompletne usługi dodatkowe, takie jak
deklaratywne transakcje i bogate strategie zapewniania trwałości.


Tworzenie testu
Każdy z rozdziałów niniejszej książki zostanie zakończony stworzeniem
testu. Prawdę mówiąc, jeśli jesteś programistą, który głęboko wierzy w pi-
sanie programów w oparciu o testy, to testy modułów powinieneś tworzyć
w pierwszej kolejności. Wielu z Was kupiło tę książkę, gdyż Spring jest
w stanie poprawić łatwość testowania aplikacji. W zasadzie poprawa
możliwości testowania od samego początku stanowiła jedno z podsta-
wowych założeń architektury frameworka Spring.
Automatyzacja testów da Ci większą pewność co do tego, że Twój kod
działa poprawnie, a co więcej, że będzie działać poprawnie także po
wprowadzeniu zmian. W rzeczywistości wszyscy Twoi szefowie czytają
te same książki, które informują, że utrzymywanie dużych zespołów te-
stujących jest kosztowne. My musimy przejąć tę pałeczkę. Nie ma żadnego
efektywnego sposobu testowania, który by nie korzystał z automatyzacji.
Niemniej jednak istnieje pewnie poważny problem. Wiele spośród obecnie
stosowanych architektur, takich jak EJB oraz Struts, raczej nie ułatwiają
testowania. Ich czas ładowania jest długi, a tworzenie obiektów zastęp-
czych (ang. mock objects) jest trudne.
Jednak Spring diametralnie zmienia tę sytuację. Każdy obiekt może być
wykorzystany poza środowiskiem kontenera. Co więcej, ze względy na
to, że kontener jest taki „lekki”, koszty związane z jego uruchamianiem



                                                            Tworzenie testu   35
są pomijalnie małe. To niezwykle duża zaleta, zwłaszcza jeśli musimy
     testować tworzony kod. W końcu Spring zachęca i wspiera model pro-
     gramowania o bardzo słabych powiązaniach pomiędzy komponentami.

     Jak to zrobić?
     Test modułu (test jednostkowy, ang. unit test) można sobie wyobrazić
     jako kolejnego klienta aplikacji. Testy przyjmują pewne założenia odno-
     śnie warunków, jakie powinny być spełnione w przypadku, gdy aplika-
     cja będzie działać poprawnie. Na przykład, jeśli dodajesz obiekt do listy,
     to jej wielkość powinna się zwiększyć o jeden. Następnie test można
     wykonać samodzielnie podczas dodawania do kodu kolejnej funkcji,
     bądź też, podczas testowania starego kodu. Testy można także wykonywać
     jako jeden z elementów całego procesu kompilacji i przygotowywania
     aplikacji. W takim przypadku, jeśli założenia przyjęte w testach nie zo-
     staną spełnione, to cały proces przygotowywania aplikacji zakończy się
     niepowodzeniem.
     Każdy test modułu jest klasą dziedziczącą po klasie TestCase. Listing
     1.11 przedstawia test stanowiący klienta fasady.

     Listing 1.11. RentABikeTest.java
         import java.util.List;
         import junit.framework.TestCase;

         public class RentABikeTest extends TestCase {
            private RentABike rentaBike;

             public void setUp() {
                rentaBike = new ArrayListRentABike("Rowery Bruce'a");
             }

             public void testGetName() {
                assertEquals("Rowery Bruce'a", rentaBike.getStoreName());
             }

             public void testGetBike() {
                Bike bike = rentaBike.getBike("11111");
                assertNotNull(bike);
                assertEquals("Shimano", bike.getManufacturer());
             }

             public void testGetBikes() {
                List bikes = rentaBike.getBikes();



36   Rozdział 1: Początki
assertNotNull(bikes);
               assertEquals(3, bikes.size());
           }
       }

Następnie, aby uruchomić test, konieczne będzie zmodyfikowanie skryptu
programu Ant. Listing 1.12 przedstawia zmienione zadania inicjalizacji
i kompilacji oraz dodatkowe zadanie odpowiadające za kompilację testu
(trzeba zauważyć, iż wyrażenia ŚCIEŻKA_DO_SPRING i ŚCIEŻKA_DO_JUNIT
należy zastąpić faktycznymi ścieżkami).

Listing 1.12. build.xml
       <property name="test.class.dir" value="${test.dir}/classes"/>
       <property name="spring.dir" value="ŚCIEŻKA_DO_SPRING"/>

       <path id="bikestore.class.path">
         <fileset dir="${spring.dir}/dist">
           <include name="*.jar" />
         </fileset>

         <pathelement location="${spring.dir}/lib/jakarta-commons/commons-
          logging.jar"/>
         <pathelement location="${spring.dir}/lib/log4j/log4j-1.2.8.jar"/>
         <pathelement location="${spring.dir}/lib/j2ee/servlet.jar"/>1
         <dirset dir="${basedir}"/>
         <dirset dir="${class.dir}"/>
       </path>

       <path id="run.class.path">
          <path refid="bikestore.class.path"/>
          <dirset dir="${class.dir}"/>
       </path>

       <path id="junit.class.path">
          <path refid="run.class.path"/>
          <pathelement location="ŚCIEŻKA_DO_JUNIT"/>
       </path>

       <target name="init">
          <mkdir dir="${class.dir}" />
          <mkdir dir="${test.class.dir}" />
       </target>

       <target name="compile" depends="init"



1
    W najnowszej wersji frameworka Spring dostępnej w chwili przygotowywania polskiego wy-
    dania niniejszej książki (1.2.6) zamiast servlet.jar powinno być servlet-api.jar —
    przyp. red.


                                                                          Tworzenie testu    37
description="Compiles all source code.">
                 <javac srcdir="${src.dir}"
                      destdir="${test.class.dir}"
                        classpathref="bikestore.class.path"/>
         </target>

         <target name="compile.test" depends="init" description="Compiles all unit
         test source">
            <javac srcdir="${test.dir}"
                   destdir="${test.class.dir}"
                   classpathref="junit.class.path"/>
         </target>

     Listing 1.13 przedstawia zadanie odpowiadające za wykonanie testu.
         <target name="test" depends="compile, compile.test"
            description="Runs the unit tests">
            <junit printsummary="withOutAndErr" haltonfailure="no"
               haltonerror="no" fork="yes">
               <classpath refid="junit.class.path"/>
               <formatter type="xml" usefile="true" />
               <batchtest todir="${test.dir}">
                   <fileset dir="${test.class.dir}">
                      <include name="*Test.*"/>
                   </fileset>
               </batchtest>
            </junit>
         </target>

     A oto wyniki testu:
         Buildfile: build.xml

         init:

         compile:

         compile.test:

         test:
             [junit] Running RentABikeTest
             [junit] Test run: 3, Failures: 0, Errors: 0; Time elapsed: 0.36 sec

         BUILD SUCCESSFUL
         Total time: 2 seconds


     Jak to działa?
     Ant właśnie przygotował całą aplikację, w tym także test. Następnie te-
     sty zostały wykonane. Wszystko zakończyło się powodzeniem. Gdyby
     testów nie udało się przeprowadzić pomyślnie, to aby cały proces przy-
     gotowywania aplikacji mógł się poprawnie zakończyć, konieczne byłoby

38   Rozdział 1: Początki
takie poprawienie jej kodu, by warunki określane w testach zostały speł-
nione. W ten sposób można wychwytywać i poprawiać niewielkie błędy,
zanim przerodzą się one w duże problemy.
W następnym rozdziale zaczniemy na poważnie korzystać z frameworka
Spring. Stworzymy prawdziwy interfejs użytkownika dla naszej aplikacji,
wykorzystując do tego celu szkielet Web MVC wchodzący w skład Springa.
Pokażemy także, w jaki sposób można zintegrować ze Springiem istnie-
jące komponenty interfejsu użytkownika.




                                                           Tworzenie testu   39

More Related Content

PDF
Spring Framework. Profesjonalne tworzenie oprogramowania w Javie
PDF
Macromedia Flash 8 ActionScript. Oficjalny podręcznik
PDF
ActionScript 2.0. Od podstaw
PDF
J2EE. Vademecum profesjonalisty. Wydanie II
PDF
ASP.NET 2.0. Gotowe rozwiązania
PDF
100 sposobów na Visual Studio
PDF
.NET Framework 2.0. Zaawansowane programowanie
PDF
Java Data Objects
Spring Framework. Profesjonalne tworzenie oprogramowania w Javie
Macromedia Flash 8 ActionScript. Oficjalny podręcznik
ActionScript 2.0. Od podstaw
J2EE. Vademecum profesjonalisty. Wydanie II
ASP.NET 2.0. Gotowe rozwiązania
100 sposobów na Visual Studio
.NET Framework 2.0. Zaawansowane programowanie
Java Data Objects

What's hot (7)

PDF
Visual Basic 2005. Zapiski programisty
PDF
Flash i PHP5. Podstawy
PDF
Ajax w akcji
PDF
ASP.NET 2.0. Księga eksperta
PDF
Visual Basic .NET. Encyklopedia
PDF
Serwisy internetowe. Programowanie
PDF
JavaServer Faces. Wydanie II
Visual Basic 2005. Zapiski programisty
Flash i PHP5. Podstawy
Ajax w akcji
ASP.NET 2.0. Księga eksperta
Visual Basic .NET. Encyklopedia
Serwisy internetowe. Programowanie
JavaServer Faces. Wydanie II
Ad

Viewers also liked (20)

PDF
letter_ECJ
PPS
Dworek Sojecki
PPTX
Maty W Dwóch Posunięciach
PPS
Dziwy natury
PPTX
Między adaptacją a oporem
PDF
Tworzenie stron WWW. Biblia. Wydanie II
PPTX
Zielone przedszkole oferta
PPTX
Marcin kriger
PDF
Referencia Dupont 2015
PPS
Dzień dobry
PDF
Dwr中文文档
DOC
Telewizja: mogło być inaczej
PPS
Dzień Szantusia
PDF
Nik p-14-022-egzaminy-zewnetrzne
PDF
Cleantech Business Park
PPT
Hupp 2
PDF
The 2 nd wonder in Brodnica
PDF
Rozwoj pomorza zachodniego_2015_2016
ODP
Git nie dla początkujących
letter_ECJ
Dworek Sojecki
Maty W Dwóch Posunięciach
Dziwy natury
Między adaptacją a oporem
Tworzenie stron WWW. Biblia. Wydanie II
Zielone przedszkole oferta
Marcin kriger
Referencia Dupont 2015
Dzień dobry
Dwr中文文档
Telewizja: mogło być inaczej
Dzień Szantusia
Nik p-14-022-egzaminy-zewnetrzne
Cleantech Business Park
Hupp 2
The 2 nd wonder in Brodnica
Rozwoj pomorza zachodniego_2015_2016
Git nie dla początkujących
Ad

Similar to Spring. Zapiski programisty (20)

PDF
Java. Tworzenie aplikacji sieciowych za pomocą Springa, Hibernate i Eclipse
PDF
J2EE. Stosowanie wzorców projektowych
PDF
J2EE. Podstawy programowania aplikacji korporacyjnych
PDF
J2EE. Wzorce projektowe. Wydanie 2
PDF
Java 2. Techniki zaawansowane. Wydanie II
PDF
Java. Aplikacje bazodanowe. Najlepsze rozwiązania
PDF
Java. Usługi WWW. Vademecum profesjonalisty
PDF
Java. Techniki zaawansowane. Wydanie VIII
PDF
J2EE. Wzorce projektowe
PDF
Hibernate w akcji
PDF
Eclipse Web Tools Platform. Tworzenie aplikacji WWW w języku Java
PDF
JBuilder. Vademecum profesjonalisty
PDF
Praktyczny kurs Java
PDF
Visual C# 2005. Zapiski programisty
PDF
Java 2. Techniki zaawansowane
PDF
PHP5. Zaawansowane programowanie
PDF
JBuilder i bazy danych
PDF
Struktury danych i techniki obiektowe na przykładzie Javy 5.0
PPT
User Experience – wpływ internetu na aplikacje enterprise - Netcamp #14
PDF
Po prostu Java 2
Java. Tworzenie aplikacji sieciowych za pomocą Springa, Hibernate i Eclipse
J2EE. Stosowanie wzorców projektowych
J2EE. Podstawy programowania aplikacji korporacyjnych
J2EE. Wzorce projektowe. Wydanie 2
Java 2. Techniki zaawansowane. Wydanie II
Java. Aplikacje bazodanowe. Najlepsze rozwiązania
Java. Usługi WWW. Vademecum profesjonalisty
Java. Techniki zaawansowane. Wydanie VIII
J2EE. Wzorce projektowe
Hibernate w akcji
Eclipse Web Tools Platform. Tworzenie aplikacji WWW w języku Java
JBuilder. Vademecum profesjonalisty
Praktyczny kurs Java
Visual C# 2005. Zapiski programisty
Java 2. Techniki zaawansowane
PHP5. Zaawansowane programowanie
JBuilder i bazy danych
Struktury danych i techniki obiektowe na przykładzie Javy 5.0
User Experience – wpływ internetu na aplikacje enterprise - Netcamp #14
Po prostu Java 2

More from Wydawnictwo Helion (20)

PDF
Tworzenie filmów w Windows XP. Projekty
PDF
Blog, więcej niż internetowy pamiętnik
PDF
Access w biurze i nie tylko
PDF
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
PDF
E-wizerunek. Internet jako narzędzie kreowania image&#39;u w biznesie
PDF
Microsoft Visual C++ 2008. Tworzenie aplikacji dla Windows
PDF
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
PDF
Makrofotografia. Magia szczegółu
PDF
Windows PowerShell. Podstawy
PDF
Java. Efektywne programowanie. Wydanie II
PDF
JavaScript. Pierwsze starcie
PDF
Ajax, JavaScript i PHP. Intensywny trening
PDF
PowerPoint 2007 PL. Seria praktyk
PDF
Excel 2007 PL. Seria praktyk
PDF
Access 2007 PL. Seria praktyk
PDF
Word 2007 PL. Seria praktyk
PDF
Serwisy społecznościowe. Budowa, administracja i moderacja
PDF
AutoCAD 2008 i 2008 PL
PDF
Bazy danych. Pierwsze starcie
PDF
Inventor. Pierwsze kroki
Tworzenie filmów w Windows XP. Projekty
Blog, więcej niż internetowy pamiętnik
Access w biurze i nie tylko
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
E-wizerunek. Internet jako narzędzie kreowania image&#39;u w biznesie
Microsoft Visual C++ 2008. Tworzenie aplikacji dla Windows
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
Makrofotografia. Magia szczegółu
Windows PowerShell. Podstawy
Java. Efektywne programowanie. Wydanie II
JavaScript. Pierwsze starcie
Ajax, JavaScript i PHP. Intensywny trening
PowerPoint 2007 PL. Seria praktyk
Excel 2007 PL. Seria praktyk
Access 2007 PL. Seria praktyk
Word 2007 PL. Seria praktyk
Serwisy społecznościowe. Budowa, administracja i moderacja
AutoCAD 2008 i 2008 PL
Bazy danych. Pierwsze starcie
Inventor. Pierwsze kroki

Spring. Zapiski programisty

  • 1. IDZ DO PRZYK£ADOWY ROZDZIA£ SPIS TREŒCI Spring. Zapiski programisty KATALOG KSI¥¯EK Autorzy: Bruce A. Tate, Justin Gehtland T³umaczenie: Piotr Rajca KATALOG ONLINE ISBN: 83-246-0336-0 Tytu³ orygina³u: Spring: A Developers Notebook ZAMÓW DRUKOWANY KATALOG Format: B5, stron: 272 TWÓJ KOSZYK Przyspiesz tworzenie aplikacji w Javie DODAJ DO KOSZYKA • Uproœæ okreœlanie zale¿noœci pomiêdzy klasami • Zastosuj narzêdzie Hibernate do usprawnienia komunikacji z bazami danych • Wykorzystaj mo¿liwoœci programowania aspektowego CENNIK I INFORMACJE Technologia J2EE mia³a w za³o¿eniu byæ prosta i szybka w u¿ytkowaniu. Praktyka jednak okaza³a siê daleka od teorii. Mozolne tworzenie aplikacji wykorzystuj¹cych ZAMÓW INFORMACJE dziesi¹tki interfejsów po³¹czonych wzajemnymi zale¿noœciami, setki deskryptorów O NOWOŒCIACH wdro¿enia oraz plików pomocniczych spowodowa³o, ¿e zaczêto poszukiwaæ rozwi¹zañ alternatywnych. Jednym z nich okaza³ siê framework Spring, zyskuj¹cy coraz wiêksz¹ ZAMÓW CENNIK popularnoœæ wœród programistów Javy. Spring jest znacznie du¿o prostszy od wielu alternatywnych rozwi¹zañ J2EE, znacznie u³atwia testowanie aplikacji, i pozwala na usuwanie zale¿noœci z kodu oraz oddzielanie ich od serwera aplikacji. Spring umo¿liwia CZYTELNIA równie¿ wykorzystanie programowania aspektowego. FRAGMENTY KSI¥¯EK ONLINE Ksi¹¿ka „Spring. Zapiski programisty” to praktyczny przewodnik po mo¿liwoœciach tego œrodowiska. Jeœli wolisz poznawaæ nowe zagadnienia w sposób praktyczny, a nie wertuj¹c setki stron zape³nionych teoretycznymi wywodami, to ta ksi¹¿ka jest w³aœnie dla Ciebie. Znajdziesz w niej omówienie zagadnieñ zwi¹zanych z samym Springiem, wspó³pracuj¹cymi z nim narzêdziami i sposobami wykorzystania ich w procesie tworzenia aplikacji J2EE — pocz¹wszy do graficznego interfejsu u¿ytkownika i interfejsu sieciowego, a skoñczywszy na dostêpie do relacyjnych baz danych. • Tworzenie klas z zastosowaniem zale¿noœci • Budowanie interfejsu u¿ytkownika • Integrowanie JSF z frameworkiem Spring • Dostêp do baz danych za pomoc¹ JDBC • Odwzorowanie baz danych na obiekty za pomoc¹ Hibernaete Wydawnictwo Helion • Obs³uga i zabezpieczanie transakcji ul. Chopina 6 • Wysy³anie i odbieranie wiadomoœci e-mail 44-100 Gliwice tel. (32)230-98-63 Jeœli poszukujesz wydajniejszych metod tworzenia aplikacji J2EE, wykorzystaj e-mail: helion@helion.pl mo¿liwoœci frameworka Spring. Dziêki tej ksi¹¿ce poznasz je wszystkie.
  • 2. Spis treści Przedmowa ............................................................................................ 5 Wstęp .................................................................................................... 9 Rozdział 1. Początki ............................................................................. 17 Tworzenie dwóch klas przy wykorzystaniu zależności ....................... 18 Stosowanie wstrzykiwania zależności ................................................ 23 Automatyzacja przykładu ................................................................... 28 Wstrzykiwanie zależności przy wykorzystaniu frameworka Spring ... 32 Tworzenie testu ................................................................................... 35 Rozdział 2. Tworzenie interfejsu użytkownika ..................................... 41 Konfiguracja Tomcata ......................................................................... 42 Tworzenie widoku przy wykorzystaniu Web MVC ............................. 46 Wzbogacanie aplikacji sieciowych ...................................................... 56 Testowanie .......................................................................................... 65 Rozdział 3. Integracja innych klientów ................................................ 69 Tworzenie interfejsu użytkownika w oparciu o framework Struts ....... 70 Stosowanie JSF wraz z frameworkiem Spring ....................................... 83 Integracja JSF z frameworkiem Spring ............................................... 92 Rozdział 4. Stosowanie JDBC ............................................................... 95 Konfiguracja bazy danych i utworzenie schematu .............................. 96 Stosowanie szablonów JDBC frameworka Spring .............................. 101 Wydzielanie często używanego kodu ................................................ 108 Stosowanie obiektów dostępowych .................................................... 110 Wykonywanie testów przy użyciu szkieletu EasyMock .................... 116 3
  • 3. Rozdział 5. Odwzorowania obiektowo-relacyjne ................................ 121 Integracja frameworka iBATIS ..........................................................123 Stosowanie frameworka Spring z JDO ...............................................134 Stosowanie frameworków Hibernate oraz Spring ..............................142 Testowanie ........................................................................................150 Rozdział 6. Usługi i AOP ..................................................................... 151 Tworzenie usługi ...............................................................................152 Konfiguracja usługi ...........................................................................159 Stosowanie automatycznych obiektów pośredniczących ....................164 Porady operujące na wyjątkach .........................................................167 Testowanie usługi przy wykorzystaniu obiektów zastępczych ..........170 Testowanie usługi mającej efekty uboczne ........................................174 Rozdział 7. Transakcje i bezpieczeństwo ........................................... 177 Programowa obsługa transakcji ........................................................178 Konfiguracja prostych transakcji .......................................................182 Transakcje obejmujące kilka baz danych ..........................................184 Zabezpieczenie serwletów aplikacji ...................................................190 Zabezpieczanie metod aplikacji .........................................................200 Tworzenie obiektu przechwytującego ułatwiającego testowanie ........206 Rozdział 8. Obsługa wiadomości i praca zdalna ................................ 211 Wysyłanie wiadomości poczty elektronicznej ....................................212 Praca zdalna .....................................................................................216 Stosowanie JMS .................................................................................219 Testowanie aplikacji JMS ..................................................................224 Rozdział 9. Tworzenie grubych klientów ............................................ 229 Zaczynamy pracę ..............................................................................229 Tworzenie widoku BikeNavigator ......................................................244 Tworzenie formularzy edytora rowerów ...........................................249 Skorowidz ......................................................................................... 259 4 Spis treści
  • 4. ROZDZIAŁ 1. Początki W tym rozdziale: Tworzenie dwóch klas przy wykorzystaniu zależności Stosowanie wstrzykiwania zależności Automatyzacja przykładu Wstrzykiwanie zależności przy wykorzystaniu frameworka Spring Tworzenie testu W weekendy z wielkim zapałem oddaję się sportom ekstremalnym. We- dług standardów właściwych dla osób przeciętnych, robiłem na rowerze górskim naprawdę zwariowane rzeczy, a oprócz tego uwielbiam kaja- karstwo górskie. Tylko raz znalazłem się w poważnych kłopotach. Spływa- łem na rzece o nazwie Piedra, na której byłem po raz pierwszy, w nowym sprzęcie i z głową naładowaną nowymi technikami. W kajakarstwie górskim przeżycie zależy od zachowania prostoty i szybkości, a ja byłem niepewny i wolny. Zamiast atakować rzekę, to ona zaatakowała mnie; przepłynąłem przez trzy bystrza klasy IV i naprawdę miałem szczęście, że wyszedłem z tego bez żadnych obrażeń. Szybkość i prostota ma równie duże znaczenie w przypadku tworzenia oprogramowania. Spring Framework daje mi jedno i drugie. Kupiłeś tę książkę, więc zapewne zgadzasz się z tym stwierdzeniem. Spring, choć jest prosty, ma bardzo duże możliwości. Ogromne. Spring pozwoli Ci na pi- sanie aplikacji o architekturze warstwowej, w której poszczególne warstwy 17
  • 5. będę wyraźnie od siebie oddzielone. Spring sprawia, że będziesz mógł testować tworzony kod w tak prosty i przejrzysty sposób, o jakim wcze- śniej nawet nie mogłeś marzyć. W niniejszym rozdziale stworzysz pro- stą aplikację, zautomatyzujesz proces jej kompilacji i przystosujesz ją do korzystania z frameworka Spring. Spring jest najpopu- larniejszym produk- Tworzenie dwóch klas tem z nowej grupy tak zwanych przy wykorzystaniu zależności lekkich kontenerów. Wielu nauczycieli i konsultantów pisze o zależnościach jako o czymś, co Jeśli uwzględnimy wszystkie wchodzą- można by porównać do majonezu zbyt długo pozostawionego na słońcu. ce w jego skład mo- Jednak jeśli tworzona aplikacja ma robić cokolwiek interesującego, to za- duły, to się okaże, że Spring nie jest aż leżności muszą się w niej pojawić. Cała sztuka polega na tym, by ziden- taki „lekki”, jednak tyfikować ważne zależności i obsłużyć je w odpowiedni sposób. Sposób, w tym przypadku w jaki rozwiążesz zależności, będzie mieć znaczący wpływ na łatwość określenie to odnosi się do tego wszyst- utrzymania aplikacji, jej rozbudowy oraz testowania. Podczas lektury kiego, co zazwyczaj niniejszej książki napiszesz system rezerwacji rowerów górskich. Sklep trzeba dodawać do sportowy mógłby korzystać z takiego systemu do rezerwacji i wypożyczania kodu umieszczanego i wykonywanego rowerów. Zaczniemy od najprostszych rozwiązań, w których wszystkie w kontenerze. zależności będą określone na stałe w kodzie; w ten sposób będziemy mogli się upewnić, że używana infrastruktura działa poprawnie. Następnie roz- luźnimy powiązania za pomocą frameworka Spring i stopniowo będzie- my dodawać do naszej aplikacji trwałość, warstwę prezentacji sieciowej, deklaratywne transakcje i kilka innych usług. Dla mnie tworzenie przy wykorzystaniu frameworka Spring ma charakter iteracyjny. Najbliższych kilka ćwiczeń jest poświęconych powolnemu przygotowywaniu infrastruktury. W pierwszym upewnimy się, że dys- ponujemy poprawnie skonfigurowanym oraz działającym środowiskiem Javy i zaczniemy tworzyć podstawowy model aplikacji. Każdy z kilku pierwszych przykładów jest poświęcony niewielkiemu fragmentowi śro- dowiska, co ułatwi nam rozwiązywanie ewentualnych problemów, gdyby jakieś się pojawiły. 18 Rozdział 1: Początki
  • 6. Jak to osiągnąć? Zaczniemy od dwóch klas umieszczonych w jednym katalogu. Pierwsza z nich będzie reprezentować rower górski, a druga rejestr, w którym będą przechowywane informacje o wszystkich rowerach. Tę drugą klasę na- zwiemy fasadą. Informacje o posiadanych rowerach będą podawane w konstruktorze fasady, a następnie wyświetlane przy wykorzystaniu trzeciej, bardzo prostej klasy. Klasa Bike, reprezentująca rower, została przedstawiona na listingu 1.1. Listing 1.1. Bike.java public class Bike { private String manufacturer; private String model; private int frame; private String serialNo; private double weight; private String status; public Bike() {} public Bike(String manufacturer, String model, int frame, String serialNo, double weight, String status) { this.manufacturer = manufacturer; this.model = model; this.frame = frame; this.serialNo = serialNo; this.weight = weight; this.status = status; } public String toString() { return "Rower : " + "producent -- " + manufacturer + "n: model -- " + model + "n: rama -- " + frame + "n: numer seryjny -- " + serialNo + "n: waga -- " + weight + "n: status -- " + status + ".n"; } public String getManufacturer() { return manufacturer; } public void setManufacturer(String manufacturer) { this.manufacturer = manufacturer; } Tworzenie dwóch klas przy wykorzystaniu zależności 19
  • 7. public String getModel() { return model; } public void setModel(String model) { this.model = model; } public int getFrame() { return frame; } public void setFrame(int frame) { this.frame = frame; } public String getSerialNo() { return serialNo; } public void setSerialNo(String serialNo) { this.serialNo = serialNo; } public double getWeight() { return weight; } public void setWeight(double weight) { this.weight = weight; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } } Listing 1.2 przedstawia fasadę. Listing 1.2. RentABike.java import java.util.Iterator; import java.util.List; import java.util.ArrayList; public class RentABike { private String storeName; final List bikes = new ArrayList(); public RentABike(String storeName) { this.storeName = storeName; bikes.add(new Bike("Shimano", "Roadmaster", 20, "11111", 15, "Dobry")); bikes.add(new Bike("Cannondale", "F2000 XTR", 18, "22222",12, "Doskonały")); bikes.add(new Bike("Trek","6000", 19, "33333", 12.4, "Dobry")); } public String toString() { return "RentABike: " + storeName; } public List getBikes() { return bikes; } public Bike getBike(String serialNo) { Iterator iter = bikes.iterator(); while(iter.hasNext()) { Bike bike = (Bike)iter.next(); if(serialNo.equals(bike.getSerialNo())) return bike; 20 Rozdział 1: Początki
  • 8. } return null; } } I w końcu kod zamieszczony na listingu 1.3 przedstawia widok. Listing 1.3. CommandLineView.java import java.util.Iterator; public class CommandLineView { private RentABike rentaBike; Klasa RentABike public CommandLineView() {rentaBike = new RentABike("Rowery Bruce'a");} jest zależnością. W przypadku sto- public void printAllBikes() { sowania takiego System.out.println(rentaBike.toString()); Iterator iter = rentaBike.getBikes().iterator(); stylu programowa- while(iter.hasNext()) { nia zależności są Bike bike = (Bike)iter.next(); podawane na stałe, System.out.println(bike.toString()); co zwiększa stopień } wzajemnego powią- } zania fasady i wido- public static void main(String[] args) { ku. Framework CommandLineView clv = new CommandLineView(); Spring pomoże clv.printAllBikes(); nam wyeliminować } zależności } takiego typu. Teraz możesz już skompilować aplikację, używając następującego polecenia: C:PozyczRowerAppsrc javac -d ..out *.java Katalog wynikowy będzie teraz zawierać skompilowane pliki klas: Katalog: C:PozyczRowerAppout 2005-12-27 08:17 <DIR> . 2005-12-27 08:17 <DIR> .. 2005-12-27 08:17 1 753 Bike.class 2005-12-27 08:17 1 442 RentABike.class 2005-12-27 08:17 937 CommandLineView.class Aplikację możesz uruchomić w następujący sposób: C:PozyczRowerAppout> java CommandLineView RentABike: Rowery Bruce'a Rower : producent -- Shimano : model -- Roadmaster : rama -- 20 : numer seryjny -- 11111 : waga -- 15.0 : status -- Dobry. Tworzenie dwóch klas przy wykorzystaniu zależności 21
  • 9. Rower : producent -- Cannondale : model -- F2000 XTR : rama -- 18 : numer seryjny -- 22222 : waga -- 12.0 : status -- Doskonały. Rower : producent -- Trek : model -- 6000 : rama -- 19 : numer seryjny -- 33333 : waga -- 12.4 : status -- Dobry. Jak to działa? Nic dobrego. Nasz aktualny projekt jest bardzo prosty, lecz jednocześnie wszystkie powiązania są określone na stałe. Od razu można wskazać kilka wad takiego rozwiązania: • Warstwa fasady (RentABike) w statyczny sposób tworzy rowery do- Podstawowy stępne w sklepie, a zatem, za każdym razem, gdy pojawi się jakiś wzorzec projektowy nowy rower (ech!), bądź też gdy użytkownik „skasuje” jakiś rower stosowany we frameworku Spring (co za pech!), konieczne będzie wprowadzanie odpowiednich zmian oraz innych lekkich w kodzie. kontenerach, bazuje na zmniejszeniu • Także przetestowanie modelu będzie kłopotliwe, gdyż zbiór rowerów stopnia powiązań jest stały i niezmienny. pomiędzy zależnościami. • Interfejs użytkownika oraz fasada są ze sobą ściśle powiązane. Można wskazać podaną na stałe zależność pomiędzy warstwą fasady i in- terfejsem użytkownika. • Kod źródłowy nie jest w żaden sposób zorganizowany, a proces kom- pilacji aplikacji nie jest zautomatyzowany. Jednak teraz chcemy wprowadzić pewne ułatwienia, by poprawić dzia- łanie środowiska Javy, tworząc jednocześnie podwaliny naszej aplikacji. W następnym przykładzie rozdzielimy poszczególne warstwy aplikacji i zautomatyzujemy proces jej kompilacji. 22 Rozdział 1: Początki
  • 10. A co z… … przygotowaniem tego całego burrito raz a dobrze? Możesz zdecydo- wać, by jednocześnie zainstalować Spring, Hiberanate, Javę, Ant oraz JUtil. Jednak z własnego doświadczenia mogę stwierdzić, że zajmując się kolejno każdym zagadnieniem z osobna, w rzeczywistości oszczędzamy czas; zwłaszcza jeśli tworzymy podstawy środowiska pracy. Kiedy wszyst- kie narzędzia zostaną już zainstalowane i będą działać poprawnie, będziesz mógł połączyć kilka czynności. Stosowanie wstrzykiwania zależności Kiedy zaczynam tworzyć aplikację, zazwyczaj jej poszczególne elementy są ze sobą ściśle powiązane. Nie ma w tym nic złego. W każdej chwili mogę to zmienić w późniejszych etapach pracy. W niniejszym przykła- dzie zmienię strukturę aplikacji w taki sposób, aby współpracowała z frameworkiem Spring w przypadku, gdy zostanie on wykorzystany. W tym celu dodam do warstwy fasady interfejs, aby mogła ona imple- mentować kilka różnych strategii. Wiele osób, gdy po raz pierwszy styka Pierwszym krokiem podczas poznawania frameworka Spring jest po- się z wstrzykiwa- niem zależności, znanie wzorca wstrzykiwania zależności (ang. dependency injection). dziwi się: „O co tyle Nie jest on skomplikowany, choć ma kluczowe znaczenie. Jest on na tyle hałasu?”. Jednak odmienny od standardowo przyjętego sposobu kodowania, że zapewne kiedy zaczną uży- wać tej techniki, będziesz chciał zanotować sobie skrócone informacje na jego temat. po pewnym czasie zrozumieją, iż ta Rysunek 1.1 przedstawia klienta i serwer przygotowane do wykorzysta- prosta zmiana nia techniki wstrzykiwania zależności. Klient używa innej klasy, którą może w ogromnym będziemy nazywali usługą. Klient posiada właściwość, a w niej można stopniu poprawić zapisać referencję do usługi. Usługa jest z kolei reprezentowana przez tworzony kod i ułatwić utrzymanie interfejs, co sprawia, że klient nie zna jej faktycznej implementacji. aplikacji. Niemniej jednak taki kod nie cechuje się niskim stopniem powiązań — wciąż w jakiś sposób musimy utworzyć usługę. Dzięki wstrzykiwaniu zależności jakieś dodatkowe narzędzie, nazywane asemblerem lub kon- tenerem, odpowiada za utworzenie zarówno klienta, jak i usługi, a na- stępnie określa wartość właściwości aService (będącej referencją do obiektu typu Service stanowiącego implementację usługi), spełniając tym samym wymagane zależności. Stosowanie wstrzykiwania zależności 23
  • 11. Rysunek 1.1. Klient używa usługi reprezentowanej przez interfejs Prawdopodobnie już zdarzało Ci się stosować taki sposób kodowania. Jednak dopiero teraz, kiedy wykorzystamy framework, który w spójny spo- sób używa tego modelu programowego w obrębie całej aplikacji, przeko- namy się, jak duże możliwości on zapewnia. Kod składający się z luźno powiązanych komponentów jest znacznie prostszy do testowania, utrzy- mania i zrozumienia. Jak to zrobić? Aby stosować ten model projektowy, wcale nie trzeba korzystać z lek- kich kontenerów. W celu rozdzielenia elementów programu przy wyko- rzystaniu wstrzykiwania zależności należy wykonać trzy czynności: 1. Stworzyć interfejs, który będzie reprezentować usługę. 2. Dodać do klienta właściwość odwołującą się do usługi. 3. Przy wykorzystaniu dodatkowego frameworka lub własnego kodu stworzyć usługę i przypisać odpowiednią wartość właściwości klienta. Pierwszym krokiem jest wydzielenie interfejsu. Teraz zmienimy nazwę pliku, definicji klasy oraz konstruktora RentABike na ArrayListRentABike (listing 1.4) i stworzymy interfejs (listing 1.5). Listing 1.4. ArrayListRentABike.java (wcześniej RentABike.java) import java.util.List; import java.util.ArrayList; import java.util.Iterator; public class ArrayListRentABike implements RentABike { private String storeName; final List bikes = new ArrayList(); public ArrayListRentABike(String storeName) { this.storeName = storeName; bikes.add(new Bike("Shimano", "Roadmaster", 20, "11111", 15, 24 Rozdział 1: Początki
  • 12. "Dobry")); bikes.add(new Bike("Cannondale", "F2000 XTR", 18, "22222",12, "Doskonały")); bikes.add(new Bike("Trek","6000", 19, "33333", 12.4, "Dobry")); } public ArrayListRentABike() { this("Rowery Bruce'a"); } public void setStoreName(String storeName) { this.storeName = storeName; } public String getStoreName() { return this.storeName; } public String toString() { return "RentABike: " + storeName; } public List getBikes() { return bikes; } public Bike getBike(String serialNo) { Iterator iter = bikes.iterator(); while(iter.hasNext()) { Bike bike = (Bike)iter.next(); if(serialNo.equals(bike.getSerialNo())) return bike; } return null; } } Listing 1.5. RentABike.java import java.util.*; public interface RentABike { List getBikes(); Bike getBike(String serialNo); } Kolejnym elementem programu jest widok, przedstawiony na listingu Teraz będziemy 1.6. Warto zauważyć, że wydzieliliśmy metody, które wyświetlają in- mogli zobaczyć usługę RentABike formacje o rowerze w wierszu poleceń. Dodaliśmy także do widoku wła- udostępnioną ściwość, w której można zapisać obiekt typu RentABike. w formie właściwo- ści. Nieco później jej Listing 1.6. CommandLineView.java wartość zostanie określona przez import java.util.*; framework Spring. public class CommandLineView { private RentABike rentaBike; public CommandLineView() {} public void setRentaBike(RentABike rentaBike) { Stosowanie wstrzykiwania zależności 25
  • 13. this.rentaBike = rentaBike; } public RentABike getRentaBike() { return this.rentaBike; } public void printAllBikes() { System.out.println(rentaBike.toString()); Iterator iter = rentaBike.getBikes().iterator(); while(iter.hasNext()) { Bike bike = (Bike)iter.next(); System.out.println(bike.toString()); } } } Tutaj możemy Ostatnim elementem aplikacji jest asembler, który tworzy wszystkie obiekty zaobserwować i określa wartość właściwości (listing 1.7). działanie wstrzyki- wania zależności. Dodatkowy kod, Listing 1.7. RentABikeAssembler.java w tym przypadku public class RentABikeAssembler { napisany przez nas, public static final void main(String[] args) { tworzy oba obiekty CommandLineView clv = new CommandLineView(); i wstrzykuje referen- RentABike rentaBike = new ArrayListRentABike("Rowery Bruce'a"); cję typu RentABike clv.setRentABike(rentaBike); do obiektu widoku. clv.printAllBikes(); } } Teraz można skompilować aplikację, wykonując następujące polecenie: C:PozyczRowerAppsrc> javac -d ..out *.java Katalog wynikowy będzie zawierać następujące, skompilowane pliki klas: Katalog: C:PozyczRowerAppout 2005-12-31 15:28 <DIR> . 2005-12-31 15:28 <DIR> .. 2006-01-02 15:02 1 737 Bike.class 2006-01-02 15:02 1 477 ArrayListRentABike.class 2006-01-02 15:02 186 RentABike.class 2006-01-02 14:58 944 CommandLineView.class 2006-01-02 14:58 496 RentABikeAssembler.class Aplikację można uruchomić w następujący sposób: C:PozyczRowerAppout>java RentABikeAssembler RentABike: Rowery Bruce'a Rower : producent -- Shimano : model -- Roadmaster : rama -- 20 : numer seryjny -- 11111 26 Rozdział 1: Początki
  • 14. : waga -- 15.0 : status -- Dobry. Rower : producent -- Cannondale : model -- F2000 XTR : rama -- 18 : numer seryjny -- 22222 : waga -- 12.0 : status -- Doskonały. Rower : producent -- Trek : model -- 6000 : rama -- 19 : numer seryjny -- 33333 : waga -- 12.4 : status -- Dobry. Jak to działa? Właśnie zobaczyłeś przykład wstrzykiwania zależności poza środowi- skiem lekkiego kontenera. Choć środowiska twórców i użytkowników lekkich kontenerów robią wiele hałasu w związku z wstrzykiwaniem zależności, to jednak pomysły leżące u podstaw tego rozwiązania są cał- kiem proste. Pisząc programy, należy używać interfejsów, a zależności nie określać samemu, lecz przy wykorzystaniu dodatkowego narzędzia. W naszych przykładach, asemblery zastąpimy w końcu frameworkiem Spring. Kiedy to się stanie, framework będzie samodzielnie wywoływać konstruktory używanych obiektów i określać występujące pomiędzy nimi zależności. Niemniej jednak na razie musimy poświęcić tej wersji apli- kacji nieco więcej uwagi. A co z… … lokalizatorami usług lub obiektami fabrykującymi? Oczywiście wstrzy- kiwanie zależności nie jest jedynym sposobem rozwiązywania zależności występujących pomiędzy obiektami. W rzeczywistości nie jest to jedyny dobry sposób rozwiązywania tego problemu. Osoby korzystające z tech- nologii J2EE wykorzystują zazwyczaj lokalizatory usług (ang. service locators). Używając tego wzorca (przedstawionego na rysunku 1.2), można przedstawić zależność w formie interfejsu, zarejestrować ją w słowniku, a następnie odszukać przy wykorzystaniu dodatkowej klasy pomocniczej nazywanej lokalizatorem (ang. locator). Nie jest to wcale złe rozwiązanie. Stosowanie wstrzykiwania zależności 27
  • 15. Rysunek 1.2. Aplikacje J2EE zarządzają zależnościami przy wykorzystaniu lokalizatorów usług Strategia wstrzykiwania zależności pozwala na zastosowanie spójnego rozwiązania i całkowite oddzielenie zależności od tworzonej aplikacji. W dalszej części rozdziału przekonasz się, w jaki sposób rozwiązanie to może pomóc w testowaniu aplikacji i tworzeniu programów zapewniają- cych dużą łatwość utrzymania i konfiguracji. W rzeczywistości wcześniejsze lekkie kontenery, takie jak Avalon, wy- korzystywały właśnie to rozwiązanie. Większość nowoczesnych konte- nerów udostępnia mechanizmy służące do wyszukiwania zależności, choć zazwyczaj preferowane są inne sposoby ich rozwiązywania. Automatyzacja przykładu Najwyższy czas na małe porządki. Aby móc pójść dalej, konieczne jest zastosowanie automatyzacji. Prawdopodobnie używasz już programu Ant. Stanowi on standaryzowany sposób organizacji wszystkich zadań, jakie należy wykonać w celu skompilowania i przygotowania aplikacji. Jeśli jeszcze nie używasz tego programu, to będziesz musiał zacząć. Ant stał się wszechobecny. Aby móc posługiwać się narzędziami pro- gramistycznymi języka Java, konieczne będzie postanie używanego przez nie „języka”. Nie mamy zamiaru zamieszczać w tym rozdziale uzasad- nienia, dlaczego warto korzystać z programu Ant, gdyż zapewnie i tak już wiele na ten temat czytałeś. 28 Rozdział 1: Początki
  • 16. Jak to zrobić? Nie ma potrzeby pobierania pakietu instalacyjnego programu Ant — można wykorzystać ten, który jest dostępny wraz z frameworkiem Spring (http://springframework.org/). W celu wykonania wszystkich przykładów zamieszczonych w tej książce będziesz potrzebował frameworka Spring w wersji 1.1 lub późniejszej. Podczas jego instalacji należy postępować zgodnie z zaleceniami dotyczącymi używanego systemu operacyjnego. Kolejnym krokiem po zainstalowaniu frameworka Spring będzie zorga- nizowanie takiej struktury katalogów, która będzie wygodna zarówno dla frameworka Spring, jak i dla tworzonej aplikacji. Zalecamy zastosowa- nie takiej samej organizacji, jaka została użyta w przykładowej aplikacji dostarczanej wraz z frameworkiem Spring, dzięki czemu zyskamy możli- wość przeanalizowania gotowego, działającego przykładu. Poniżej przed- stawiliśmy listę katalogów, z których będziemy korzystać: src W tym katalogu przechowywane są wszystkie kody źródłowe apli- kacji. Jak zwykle struktura podkatalogów umieszczonych wewnątrz tego katalogu powinna odpowiadać strukturze pakietów. test W tym katalogu przechowywane są wszystkie testy modułów. Więcej informacji dotyczących JUnit można znaleźć w ostatnim ćwiczeniu zamieszczonym pod koniec tego rozdziału. db W tym katalogu umieszczane są wszelkie zasoby związane z bazami danych — skrypty, konfiguracje oraz kody. Niektóre z nich będą pli- kami konfiguracyjnymi, inne plikami pomagającymi stworzyć bazę danych o odpowiedniej strukturze, a jeszcze inne pozwolą na zapi- sanie w bazie informacji testowych. Jeśli nasza aplikacja ma współ- pracować z kilkoma różnymi bazami danych, to dla każdej z tych baz w katalogu db zostanie utworzony odrębny podkatalog. Automatyzacja przykładu 29
  • 17. war Plik war jest typową jednostką wdrażania aplikacji sieciowych. Jeśli używasz kontenera J2EE lub kontenera serwletów, takiego jak Tomcat, to w tym katalogu będzie umieszczany plik konfiguracyjny web.xml. W tym katalogu będą umieszczane także pliki konfiguracyjne uży- wane przez framework Spring. Informacje o plikach konfiguracyjnych Springa zostały podane w ćwiczeniach zamieszczonych w dalszej części książki. Na początek rozmieść pliki wchodzące w skład naszej aplikacji w nastę- pujący sposób: • Plik RentABike.java — w katalogu src, w podkatalogach odpowia- dających strukturze pakietów. • Plik ArrayListRentABike.java — w katalogu src wraz z plikiem RentABike.java. • Plik Bike.java — w katalogu src wraz z plikiem RentABike.java. • Plik CommandLineView.java — w katalogu src wraz z plikiem RentABike.java. W końcu będzie Ci potrzebny skrypt programu Ant, który należy umie- ścić w głównym katalogu projektu. Listing 1.8 przedstawia skrypt od któ- rego zaczniemy: Listing 1.8. build.xml To właśnie w tym <?xml version="1.0"?> pliku przekażesz <project name="RentABike" default="compile" basedir="."> programowi Ant informacje dotyczą- <property name="src.dir" value="src"/> ce położenia plików <property name="test.dir" value="test"/> klas wchodzących <property name="war.dir" value="war"/> <property name="class.dir" value="${war.dir}/WEB-INF/classes"/> w skład aplikacji. Można je dołączyć <target name="init"> do pliku war aplikacji <mkdir dir="${class.dir}"/> lub wskazać bezpo- </target> średnio ich wersje instalacyjne i poin- <target name="compile" depends="init" formować użyt- description="Compiles all source code."> kowników, jakie <javac srcdir="${src.dir}" destdir="${class.dir}"/> pliki muszą wdrożyć. </target> 30 Rozdział 1: Początki
  • 18. <target name="clean" description="Erases contents of classes dir"> <delete dir="${class.dir}"/> </target> </project> W celu wykonania powyższego skryptu programu Ant należy przejść do katalogu o nazwie C:PozyczRowerApp i wydać następujące polecenie: Właśnie to nazy- wam automatyza- C:PozyczRowerApp>ant cją. Ograniczyliśmy Buildfile: build.xml całkowitą liczbę init: klawiszy, jakie nale- [mkdir] Created dir: C:PozyczRowerAppwarWEB-INFclasses ży nacisnąć w celu skompilowania compile: i przygotowania [javac] Compiling 5 source files to C:PozyczRowerAppwar aplikacji — w tym WEB-INFclasses momencie cały BUILD SUCCESSFUL proces wymaga Total time: 2 seconds naciśnięcia dokładnie czterech klawiszy. Jak to działa? Program Ant przygotował aplikację w jednym, zautomatyzowanym kroku. Jak na razie nie jest to co prawda wielkim ułatwieniem, jednak znacze- nie tej automatyzacji będzie stopniowo rosło, wraz ze wzrostem stopnia złożoności poszczególnych czynności wykonywanych w ramach kom- pilacji i przygotowywania aplikacji. Później będziesz chciał, by system samoczynnie wykonywał testy modułów, dodawał operacje związane Szczerze mówiąc, budujemy tę aplika- z prekompilacją, takie jak wzbogacenie kodów bajtowych przez JDO (patrz cję w zintegrowa- rozdział 5.) lub kopiował pliki konfiguracyjne w odpowiednie miejsca. nym środowisku programistycznym Można także wykonywać zadania specjalne w celu zainicjowania bazy o nazwie IDEA, danych lub wdrożenia pliku war na serwer aplikacji. stworzonym przez firmę JetBrains. Według nas dyspo- A co z… nuje ono najlepszymi dostępnymi możli- … faktem, że niektóre zintegrowane środowiska programistyczne w ogóle wościami refakto- nie muszą korzystać z programu Ant? Jeśli chcesz używać takich śro- ringu. Ale się nie dowisk programistycznych i nie przejmować się programem Ant, to bę- przejmuj — każdą prezentowaną wer- dziesz musiał upewnić się, że: sję aplikacji testo- waliśmy także • Kod będzie rozmieszczony w katalogach o takiej samej strukturze przy wykorzystaniu jak zastosowana przez nas, by nie pojawiły się żadne problemy z pa- skryptów kietami. programu Ant. Automatyzacja przykładu 31
  • 19. • Zintegrowane środowisko programistyczne będzie miało dostęp do wszystkich plików .jar, z których będziemy korzystać. • W dalszych rozdziałach będziesz musiał znaleźć sposób wdrażania i uruchamiania aplikacji sieciowej, oraz wykonywania testów JUnit. Od tej chwili aż do końca książki będziemy informować, kiedy konieczne będzie dodanie nowego katalogu, wykonanie aplikacji lub udostępnienie nowej biblioteki. Nie będziemy jednak opisywać, jak należy to zrobić, za- kładając, że będziesz w stanie wykorzystać do tego celu możliwości używa- nego środowiska programistycznego lub będziesz wiedzieć, jak to uczy- nić bezpośrednio w skrypcie programu Ant. Wstrzykiwanie zależności przy wykorzystaniu frameworka Spring Już niemal przygotowaliśmy naszą aplikację do zastosowania frame- worka Spring. Czas go pobrać i użyć. W tym ćwiczeniu zastąpimy obiekt RentABikeAssembler frameworkiem Spring. Kiedy zacząłem używać Springa zamiast J2EE, moje życie się odmieniło. Stałem się znacznie bardziej produktywny. Okazało się, że pisanie kodu łatwiej stało się dla mnie łatwiejsze, a tworzony przeze mnie kod jest łatwiejszy do zrozumienia dla moich klientów. Z kolei uproszczenie kodu niejednokrotnie pozwalało na jego szybsze działanie. Poza tym wprowa- dzanie jakichkolwiek zmian w kodzie stało się nieporównanie łatwiejsze. W rzeczywistości napisałem książkę o znaczeniu i zaletach lekkich fra- meworków takich jak Spring; nosi ona nazwę Better, Faster, Lighter Java i została wydana przez wydawnictwo O’Reilly. Jak to zrobić? W pierwszej kolejności należy pobrać pakiet instalacyjny frameworka Spring. Można go znaleźć na witrynie http://springframework.org/. Stamtąd należy przejść na witrynę Sourceforge, na której można znaleźć wersję frameworka dostosowaną do używanego systemu operacyjnego (podczas pisania niniejszej książki używaliśmy wersji Spring 1.1). Następnie trzeba 32 Rozdział 1: Początki
  • 20. dodać do projektu nowy katalog — warWEB-INFlib — i umieścić w nim biblioteki frameworka Spring (całą zawartość katalogu dist dostępnego w pakiecie instalacyjnym frameworka Spring). Modyfikacja poprawnie zaprojektowanej aplikacji bazującej na zwyczaj- nych, starych obiektach Javy — w skrócie POJO (ang. Plain Old Java Objects) — i przystosowanie jej do korzystania z frameworka Spring nie przysparza najmniejszych problemów. Wszystko sprowadza się do wy- konania poniższych czynności: • Zmodyfikowania kodu tak, aby korzystał ze wstrzykiwania zależności. Obiekty modelu są komponentami, a usługi — aspektami. Zazwy- czaj jednak będziesz używał jedynie komponentów. • Usunięcia kodu, który tworzy obiekty i rozwiązuje zależności. • Napisania pliku konfiguracyjnego opisującego używane komponenty i aspekty. • Odwołania się do napisanego kodu za pośrednictwem frameworka Spring. Ponieważ poszczególne elementy naszej aplikacji są już przygotowane do wykorzystania wstrzykiwania zależności, zatem zastosowanie fra- meworka Spring będzie łatwym ćwiczeniem. Po prostu zastąpimy nasz asembler wersją korzystającą z frameworka i stworzymy plik konfigu- racyjny, który zostanie umieszczony w katalogu warWEB-INF. Plik konfiguracyjny został przedstawiony na listingu 1.9. Listing 1.9. RentABike-context.xml <?xml version="1.0"?> <!DOCTYPE beans PUBLIC"-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="rentaBike" class="com.springbook.ArrayListRentABike"> <property name="storeName"><value>Rowery Bruce'a</value></property> </bean> <bean id="commandLineView" class="com.springbook.CommandLineView"> <property name="rentaBike"><ref bean="rentaBike"/></property> </bean> </beans> Wstrzykiwanie zależności przy wykorzystaniu frameworka Spring 33
  • 21. Aby uruchomić skrypt przygotowujący aplikację, należy przejść do ka- talogu PozyczRowerApp i wydać następujące polecenie: C:PozyczRowerAppant Buildfile: build.xml init: [mkdir] Created dir: C:PozyczRowerAppwarWEB-INFclasses compile: [javac] Compiling 5 source files to C:PozyczRowerAppwarWEB- INFclasses BUILD SUCCESSFUL Total time: 2 seconds Na listingu 1.10 został przedstawiony nowy asembler, który zastąpił wcześniejszą klasę RentABikeAssembler. Listing 1.10. RentABikeAssembler.java package com.springbook; import org.springframework.context.support.ClassPathXmlApplicationContext; public class RentABikeAssembler { public static final void main(String[] args) { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("RentABike-context.xml"); CommandLineView clv = (CommandLineView)ctx.getBean("commandLineView"); clv.printAllBikes(); } } Jak to działa? Być może drapiesz się po głowie i zastanawiasz, co w tym wszystkim jest takiego niezwykłego. Jednak te niewielkie zmiany architektury będą miały znaczący wpływ na cykl życia aplikacji. Korzyści wynikające z ich wprowadzenia można zauważyć niemal od razu. Nie będę Cię zanudzać i opisywać ich dokładnie. Zamiast tego napiszę o tym, co się dzieje w ukry- ciu — w sposób niezauważalny dla programisty. 34 Rozdział 1: Początki
  • 22. A co z… … Pico, Hive Mind oraz Avalonem? To wszystko są lekkie kontenery. Każdy z nich ma swoje silne i słabe punkty. Ani Avalon, ani Hive Mind nie uzyskały na tyle dużej masy krytycznej, abyś chciał myśleć o ich zastosowaniu, zwłaszcza jeśli chcesz używać usług, które są w stanie współdziałać ze sobą. Obecnie największe udziały w rynku mają frame- worki Spring oraz Pico. Programiści poszukujący samodzielnego konte- nera zazwyczaj decydują się na wykorzystanie Pico, jednak Spring po- siada najbardziej rozbudowane i kompletne usługi dodatkowe, takie jak deklaratywne transakcje i bogate strategie zapewniania trwałości. Tworzenie testu Każdy z rozdziałów niniejszej książki zostanie zakończony stworzeniem testu. Prawdę mówiąc, jeśli jesteś programistą, który głęboko wierzy w pi- sanie programów w oparciu o testy, to testy modułów powinieneś tworzyć w pierwszej kolejności. Wielu z Was kupiło tę książkę, gdyż Spring jest w stanie poprawić łatwość testowania aplikacji. W zasadzie poprawa możliwości testowania od samego początku stanowiła jedno z podsta- wowych założeń architektury frameworka Spring. Automatyzacja testów da Ci większą pewność co do tego, że Twój kod działa poprawnie, a co więcej, że będzie działać poprawnie także po wprowadzeniu zmian. W rzeczywistości wszyscy Twoi szefowie czytają te same książki, które informują, że utrzymywanie dużych zespołów te- stujących jest kosztowne. My musimy przejąć tę pałeczkę. Nie ma żadnego efektywnego sposobu testowania, który by nie korzystał z automatyzacji. Niemniej jednak istnieje pewnie poważny problem. Wiele spośród obecnie stosowanych architektur, takich jak EJB oraz Struts, raczej nie ułatwiają testowania. Ich czas ładowania jest długi, a tworzenie obiektów zastęp- czych (ang. mock objects) jest trudne. Jednak Spring diametralnie zmienia tę sytuację. Każdy obiekt może być wykorzystany poza środowiskiem kontenera. Co więcej, ze względy na to, że kontener jest taki „lekki”, koszty związane z jego uruchamianiem Tworzenie testu 35
  • 23. są pomijalnie małe. To niezwykle duża zaleta, zwłaszcza jeśli musimy testować tworzony kod. W końcu Spring zachęca i wspiera model pro- gramowania o bardzo słabych powiązaniach pomiędzy komponentami. Jak to zrobić? Test modułu (test jednostkowy, ang. unit test) można sobie wyobrazić jako kolejnego klienta aplikacji. Testy przyjmują pewne założenia odno- śnie warunków, jakie powinny być spełnione w przypadku, gdy aplika- cja będzie działać poprawnie. Na przykład, jeśli dodajesz obiekt do listy, to jej wielkość powinna się zwiększyć o jeden. Następnie test można wykonać samodzielnie podczas dodawania do kodu kolejnej funkcji, bądź też, podczas testowania starego kodu. Testy można także wykonywać jako jeden z elementów całego procesu kompilacji i przygotowywania aplikacji. W takim przypadku, jeśli założenia przyjęte w testach nie zo- staną spełnione, to cały proces przygotowywania aplikacji zakończy się niepowodzeniem. Każdy test modułu jest klasą dziedziczącą po klasie TestCase. Listing 1.11 przedstawia test stanowiący klienta fasady. Listing 1.11. RentABikeTest.java import java.util.List; import junit.framework.TestCase; public class RentABikeTest extends TestCase { private RentABike rentaBike; public void setUp() { rentaBike = new ArrayListRentABike("Rowery Bruce'a"); } public void testGetName() { assertEquals("Rowery Bruce'a", rentaBike.getStoreName()); } public void testGetBike() { Bike bike = rentaBike.getBike("11111"); assertNotNull(bike); assertEquals("Shimano", bike.getManufacturer()); } public void testGetBikes() { List bikes = rentaBike.getBikes(); 36 Rozdział 1: Początki
  • 24. assertNotNull(bikes); assertEquals(3, bikes.size()); } } Następnie, aby uruchomić test, konieczne będzie zmodyfikowanie skryptu programu Ant. Listing 1.12 przedstawia zmienione zadania inicjalizacji i kompilacji oraz dodatkowe zadanie odpowiadające za kompilację testu (trzeba zauważyć, iż wyrażenia ŚCIEŻKA_DO_SPRING i ŚCIEŻKA_DO_JUNIT należy zastąpić faktycznymi ścieżkami). Listing 1.12. build.xml <property name="test.class.dir" value="${test.dir}/classes"/> <property name="spring.dir" value="ŚCIEŻKA_DO_SPRING"/> <path id="bikestore.class.path"> <fileset dir="${spring.dir}/dist"> <include name="*.jar" /> </fileset> <pathelement location="${spring.dir}/lib/jakarta-commons/commons- logging.jar"/> <pathelement location="${spring.dir}/lib/log4j/log4j-1.2.8.jar"/> <pathelement location="${spring.dir}/lib/j2ee/servlet.jar"/>1 <dirset dir="${basedir}"/> <dirset dir="${class.dir}"/> </path> <path id="run.class.path"> <path refid="bikestore.class.path"/> <dirset dir="${class.dir}"/> </path> <path id="junit.class.path"> <path refid="run.class.path"/> <pathelement location="ŚCIEŻKA_DO_JUNIT"/> </path> <target name="init"> <mkdir dir="${class.dir}" /> <mkdir dir="${test.class.dir}" /> </target> <target name="compile" depends="init" 1 W najnowszej wersji frameworka Spring dostępnej w chwili przygotowywania polskiego wy- dania niniejszej książki (1.2.6) zamiast servlet.jar powinno być servlet-api.jar — przyp. red. Tworzenie testu 37
  • 25. description="Compiles all source code."> <javac srcdir="${src.dir}" destdir="${test.class.dir}" classpathref="bikestore.class.path"/> </target> <target name="compile.test" depends="init" description="Compiles all unit test source"> <javac srcdir="${test.dir}" destdir="${test.class.dir}" classpathref="junit.class.path"/> </target> Listing 1.13 przedstawia zadanie odpowiadające za wykonanie testu. <target name="test" depends="compile, compile.test" description="Runs the unit tests"> <junit printsummary="withOutAndErr" haltonfailure="no" haltonerror="no" fork="yes"> <classpath refid="junit.class.path"/> <formatter type="xml" usefile="true" /> <batchtest todir="${test.dir}"> <fileset dir="${test.class.dir}"> <include name="*Test.*"/> </fileset> </batchtest> </junit> </target> A oto wyniki testu: Buildfile: build.xml init: compile: compile.test: test: [junit] Running RentABikeTest [junit] Test run: 3, Failures: 0, Errors: 0; Time elapsed: 0.36 sec BUILD SUCCESSFUL Total time: 2 seconds Jak to działa? Ant właśnie przygotował całą aplikację, w tym także test. Następnie te- sty zostały wykonane. Wszystko zakończyło się powodzeniem. Gdyby testów nie udało się przeprowadzić pomyślnie, to aby cały proces przy- gotowywania aplikacji mógł się poprawnie zakończyć, konieczne byłoby 38 Rozdział 1: Początki
  • 26. takie poprawienie jej kodu, by warunki określane w testach zostały speł- nione. W ten sposób można wychwytywać i poprawiać niewielkie błędy, zanim przerodzą się one w duże problemy. W następnym rozdziale zaczniemy na poważnie korzystać z frameworka Spring. Stworzymy prawdziwy interfejs użytkownika dla naszej aplikacji, wykorzystując do tego celu szkielet Web MVC wchodzący w skład Springa. Pokażemy także, w jaki sposób można zintegrować ze Springiem istnie- jące komponenty interfejsu użytkownika. Tworzenie testu 39