Skip to content

16. Aplikacja internetowa MVC w architekturze trójwarstwowej – przykład 2

16.1. Introduction

Napisaliśmy aplikację [personnes-01] o następującej strukturze:

Warstwa [dao] implementowała listę osób zarządzaną za pomocą obiektu [ArrayList]. Dzięki temu nie musieliśmy zajmować się warstwami [dao] i [service], a mogliśmy skupić się na warstwie [web]. Chcemy rozbudować aplikację w kierunku bardziej realistycznego środowiska, w którym lista osób byłaby przechowywana w tabeli bazy danych. Będzie to wymagało zmiany warstwy [dao]. Będzie to miało wpływ na pozostałe dwie warstwy. Aby skorzystać z niezależności warstw zapewnianej przez Spring IoC, wykorzystamy aplikację [personnes-01] i skonfigurujemy ją z wykorzystaniem Spring IoC:

Nowa aplikacja będzie nosiła nazwę [personnes-02]. Gdy już zostanie napisana, wiemy, że będziemy mogli zmieniać warstwy [dao] i [service] bez konieczności modyfikowania kodu warstwy [web]. Właśnie tego szukamy.

Tworzymy nowy projekt Eclipse o nazwie [personnes-02] poprzez skopiowanie i wklejenie projektu [personnes-01], zgodnie z wyjaśnieniem w punkcie 6.2:

W projekcie [1] pojawia się plik konfiguracyjny, w którym zdefiniujemy komponenty warstw [dao] i [service]. Jego zawartość jest następująca:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <!-- klasa DAO -->
    <bean id="dao" class="istia.st.mvc.personnes.dao.DaoImpl" init-method="init"/>
    <!-- klasa usługowa -->
    <bean id="service" class="istia.st.mvc.personnes.service.ServiceImpl">
        <property name="dao">
            <ref local="dao" />
        </property>
    </bean>
</beans>
  • wiersz 5: definiuje bean o nazwie [dao] jako instancję klasy [DaoImpl]. Po utworzeniu instancji wykonywana jest metoda [init] tej instancji.
  • wiersze 7–10: definiują bean o nazwie [service] jako instancję klasy [ServiceImpl].
  • wiersze 8–10: właściwość [dao] instancji [DaoImpl] jest inicjowana odwołaniem do warstwy [dao] utworzonej w wierszu 5. Przypomnijmy, że klasa [ServiceImpl] posiada właściwość [dao] oraz odpowiadający jej setter:
public class ServiceImpl implements IService {

     // warstwa [dao]
    private IDao dao;

    public IDao getDao() {
        return dao;
    }

    public void setDao(IDao dao) {
        this.dao = dao;
    }
...

Oczywiście sam ten plik nic nie robi. Kontroler [Application] wykorzysta go w swojej metodzie [init] do utworzenia instancji warstwy [service]. Przypomnijmy poprzednią wersję metody [init] kontrolera:

@SuppressWarnings("serial")
public class Application extends HttpServlet {
...
     // usługa
    ServiceImpl service = null;

     // inicjalizacja
    @SuppressWarnings("unchecked")
    public void init() throws ServletException {
...
         // instancja warstwy [dao]
        DaoImpl dao = new DaoImpl();
        dao.init();
         // instancja warstwy [service]
        service = new ServiceImpl();
        service.setDao(dao);
    }

W wierszu 5 musieliśmy jawnie podać nazwę klasy implementującej warstwę [service], a w wierszu 12 – nazwę klasy implementującej warstwę [dao]. W Springu IoC metoda [init] przyjmuje następującą postać:

@SuppressWarnings("serial")
public class Application extends HttpServlet {
     // parametry instancji
    ...

     // usługa
    private IService service = null;

     // inicjalizacja
    @SuppressWarnings("unchecked")
    public void init() throws ServletException {
    ...
         // instancja warstwy [service]
        service = (IService) new XmlBeanFactory(new ClassPathResource("spring-config.xml")).getBean("service");
    }
  • wiersz 7: pole prywatne [service] nie jest już typu [ServiceImpl], lecz typu [IService], c.a.d. z typem interfejsu warstwy [service]. Warstwa [web] nie jest zatem już powiązana z konkretną implementacją tego interfejsu.
  • wiersz 14: inicjalizacja pola [service] na podstawie pliku konfiguracyjnego [spring-config.xml].

To jedyne zmiany, które należy wprowadzić. Zainstalujmy tę nową aplikację w Tomcacie, uruchommy go, a następnie wywołajmy adres URL [http://localhost:8080/personnes-02]:

Image

16.2. Archiwizacja aplikacji internetowej

Opracowaliśmy projekt Eclipse / Tomcat dla aplikacji trójwarstwowej:

W kolejnej wersji grupa osób zostanie umieszczona w tabeli bazy danych.

  • Będzie to wymagało przepisania warstwy [dao]. Jest to łatwe do zrozumienia.
  • Zmodyfikowana zostanie również warstwa [service]. Obecnie jej jedyną rolą jest zapewnienie zsynchronizowanego dostępu do danych zarządzanych przez warstwę [dao]. W tym celu zsynchronizowaliśmy wszystkie metody warstwy [service]. Wyjaśniliśmy, dlaczego synchronizacja ta została umieszczona w tej warstwie, a nie w warstwie [dao]. W nowej wersji warstwa [service] będzie nadal pełnić wyłącznie rolę synchronizacji dostępu, jednak będzie ona zapewniana przez transakcje bazodanowe, a nie przez synchronizację metod Java.
  • Warstwa [web] pozostanie bez zmian.

Aby ułatwić przejście z jednej wersji do drugiej, tworzymy nowy projekt Eclipse o nazwie [mvc-personnes-02B], będący kopią poprzedniego projektu [mvc-personnes-02], w którym jednak warstwy [web, service, dao, entites] zostały umieszczone w plikach .jar:

Folder [src] zawiera teraz wyłącznie plik konfiguracyjny Spring [spring-config.xml]. Wcześniej zawierał on również kod źródłowy klas Java. Elementy te zniknęły, zastąpione przez ich skompilowane wersje umieszczone w archiwach [personnes-*.jar], pokazanych w [1]:

Projekt [mvc-personnes-02B] został skonfigurowany tak, aby zawierał archiwa [personnes-*.jar ] w swoim ClassPath.

Wdrażamy projekt internetowy [mvc-personnes-02B] w środowisku Tomcat:

Aby przetestować projekt, uruchamiamy serwer Tomcat, a następnie wpisujemy adres URL [http://localhost:8080/personnes02B]:

Image

Zachęcamy czytelnika do przeprowadzenia dodatkowych testów.

W wersji z bazą danych zmienimy warstwy [service] i [dao]. Chcemy pokazać, że wystarczy wtedy zastąpić w poprzednim projekcie archiwa [personnes-dao.jar] i [personnes-service.jar] nowymi archiwami, aby nasza aplikacja działała teraz z bazą danych. Nie będziemy musieli ingerować w archiwa warstwy [web] ani warstwy [entites].