Udostępnijmy architektury aplikacji internetowych opartych na Javie!
Istnieje wiele różnych architektur aplikacji internetowych, które mają być implementowane przy użyciu języka Java. Odpowiedzi na to pytanie mogą służyć jako biblioteka różnych projektów aplikacji internetowych z ich zaletami i wadami. Chociaż zdaję sobie sprawę, że odpowiedzi będą subiektywne, starajmy się być tak obiektywni, jak tylko potrafimy, i motywować wymienione przez nas za i przeciw.
Użyj poziomu szczegółowości, który preferujesz do opisu swojej architektury. Aby Twoja odpowiedź miała jakąkolwiek wartość, musisz przynajmniej opisać główne technologie i pomysły użyte w opisywanej architekturze. I wreszcie, kiedy powinniśmy wykorzystać Twoją architekturę?
Zacznę...
Przegląd architektury
Korzystamy z 3-warstwowej architektury opartej na otwartych standardach firmy Sun, takich jak Java EE, Java Persistence API, Servlet i Java Server Pages.
- Trwałość
- Biznes
- Prezentacja
Możliwe przepływy komunikacyjne między warstwami są reprezentowane przez:
Persistence <-> Business <-> Presentation
Co na przykład oznacza, że warstwa prezentacji nigdy nie wywołuje ani nie wykonuje operacji utrwalania, zawsze robi to przez warstwę biznesową. Ta architektura ma spełniać wymagania aplikacji internetowych o wysokiej dostępności.
Trwałość
Wykonuje operacje tworzenia, odczytu, aktualizacji i usuwania ( CRUD ). W naszym przypadku używamy ( Java Persistence API ) JPA i obecnie używamy Hibernate jako naszego dostawcy trwałości i używamy jego EntityManager .
Ta warstwa jest podzielona na wiele klas, z których każda zajmuje się określonym typem jednostek (tj. Jednostki związane z koszykiem mogą być obsługiwane przez jedną klasę trwałości) i jest używana przez jednego i tylko jednego menedżera .
Ponadto warstwa ta przechowuje również podmioty WZP , które są takie rzeczy jak Account
, ShoppingCart
etc.
Biznes
Cała logika związana z funkcjonalnością aplikacji internetowej znajduje się w tej warstwie. Funkcją tą może być zainicjowanie przelewu pieniężnego dla klienta, który chce zapłacić za produkt on-line przy użyciu swojej karty kredytowej. Równie dobrze może to być utworzenie nowego użytkownika, usunięcie użytkownika lub obliczenie wyniku bitwy w grze internetowej.
Ta warstwa jest podzielona na wiele klas, a każda z tych klas jest oznaczona, @Stateless
aby stać się bezstanowym komponentem Session Bean (SLSB). Każdy SLSB jest nazywany menedżerem i na przykład menedżer może być klasą z adnotacjami, jak wspomniano AccountManager
.
Kiedy AccountManager
musi wykonać operacje CRUD, wykonuje odpowiednie wywołania wystąpienia AccountManagerPersistence
, które jest klasą w warstwie trwałości. Z grubsza można przedstawić dwie metody AccountManager
:
...
public void makeExpiredAccountsInactive() {
AccountManagerPersistence amp = new AccountManagerPersistence(...)
// Calls persistence layer
List<Account> expiredAccounts = amp.getAllExpiredAccounts();
for(Account account : expiredAccounts) {
this.makeAccountInactive(account)
}
}
public void makeAccountInactive(Account account) {
AccountManagerPersistence amp = new AccountManagerPersistence(...)
account.deactivate();
amp.storeUpdatedAccount(account); // Calls persistence layer
}
Używamy transakcji menedżera kontenerów, więc nie musimy samodzielnie rozgraniczać transakcji. Zasadniczo dzieje się to pod maską, gdy rozpoczynamy transakcję podczas wprowadzania metody SLSB i zatwierdzamy ją (lub wycofujemy) bezpośrednio przed wyjściem z metody. Jest to przykład konwencji zamiast konfiguracji, ale nie potrzebowaliśmy jeszcze niczego poza domyślną wymaganą.
Oto jak samouczek Java EE 5 firmy Sun wyjaśnia atrybut Wymaganej transakcji dla komponentów Enterprise JavaBeans (EJB):
Jeśli klient działa w ramach transakcji i wywołuje metodę komponentu bean przedsiębiorstwa, metoda jest wykonywana w ramach transakcji klienta. Jeśli klient nie jest powiązany z transakcją, kontener rozpoczyna nową transakcję przed uruchomieniem metody.
Atrybut Wymagany jest niejawnym atrybutem transakcji dla wszystkich metod komponentu bean przedsiębiorstwa działających z rozgraniczeniem transakcji zarządzanych przez kontener. Zwykle nie ustawia się atrybutu Wymagane, chyba że trzeba zastąpić inny atrybut transakcji. Ponieważ atrybuty transakcji są deklaratywne, można je później łatwo zmienić.
Prezentacja
Nasza warstwa prezentacji odpowiada za ... prezentację! Odpowiada za interfejs użytkownika i wyświetla informacje użytkownikowi, tworząc strony HTML i odbierając dane wejściowe użytkownika za pośrednictwem żądań GET i POST. Obecnie używamy kombinacji starego serwletu + Java Server Pages ( JSP ).
Warstwa wywołuje metody w menedżerach warstwy biznesowej w celu wykonania operacji żądanych przez użytkownika i otrzymania informacji do wyświetlenia na stronie internetowej. Czasami informacje otrzymane z warstwy biznesowej są mniej skomplikowanymi typami, jak te String
i int
inne, a innym razem jednostki JPA .
Plusy i minusy architektury
Plusy
- Posiadanie wszystkiego, co jest związane z określonym sposobem wykonywania trwałości w tej warstwie, oznacza tylko, że możemy zamienić używanie JPA na coś innego, bez konieczności ponownego pisania czegokolwiek w warstwie biznesowej.
- Łatwo nam zamienić naszą warstwę prezentacji na coś innego i prawdopodobnie tak się stanie, jeśli znajdziemy coś lepszego.
- Pozwolenie kontenerowi EJB na zarządzanie granicami transakcji jest przyjemne.
- Używanie Servlet + JPA jest łatwe (na początek), a technologie są szeroko stosowane i wdrażane na wielu serwerach.
- Korzystanie z Java EE ma nam ułatwić stworzenie systemu wysokiej dostępności z równoważeniem obciążenia i przełączaniem awaryjnym . Obydwoje uważamy, że musimy mieć.
Cons
- Korzystając z JPA, możesz przechowywać często używane zapytania jako nazwane zapytania, używając
@NamedQuery
adnotacji w klasie jednostki JPA. Jeśli masz jak najwięcej związanych z trwałością w klasach trwałości, tak jak w naszej architekturze, spowoduje to rozłożenie lokalizacji, w których możesz znaleźć zapytania, aby uwzględnić również encje JPA. Przegląd operacji trwałości będzie trudniejszy, a tym samym trudniejszy w utrzymaniu. - Mamy jednostki JPA jako część naszej warstwy trwałości. Ale
Account
czyShoppingCart
nie są to naprawdę obiekty biznesowe? Odbywa się to w ten sposób, że musisz dotknąć tych klas i przekształcić je w jednostki, z którymi JPA wie, jak sobie radzić. - Encje JPA, które są również naszymi obiektami biznesowymi, są tworzone jako obiekty transferu danych ( DTO ), znane również jako obiekty wartości (VO). Powoduje to anemiczny model domeny, ponieważ obiekty biznesowe nie mają własnej logiki z wyjątkiem metod akcesorów. Cała logika jest wykonywana przez naszych menedżerów w warstwie biznesowej, co skutkuje bardziej proceduralnym stylem programowania. To nie jest dobry projekt obiektowy, ale może nie stanowi to problemu? (W końcu orientacja obiektowa nie jest jedynym paradygmatem programowania, który przyniósł rezultaty).
- Używanie EJB i Java EE wprowadza trochę złożoności. I nie możemy używać wyłącznie Tomcata (dodanie mikro-kontenera EJB nie jest wyłącznie Tomcat).
- Istnieje wiele problemów z używaniem Servleta + JPA. Skorzystaj z Google, aby uzyskać więcej informacji na temat tych problemów.
- Ponieważ transakcje są zamykane przy wychodzeniu z warstwy biznesowej, nie możemy załadować żadnych informacji z jednostek JPA, które są skonfigurowane do ładowania z bazy danych, gdy jest to potrzebne (przy użyciu
fetch=FetchType.LAZY
) z warstwy prezentacji. Spowoduje to wyjątek. Przed zwróceniem encji zawierającej tego typu pola musimy upewnić się, że wywołaliśmy odpowiednie metody pobierające. Inną opcją jest użycie Java Persistence Query Language ( JPQL ) i wykonanieFETCH JOIN
. Jednak obie te opcje są nieco uciążliwe.