Lassen Sie uns Java-basierte Webanwendungsarchitekturen teilen!
Es gibt viele verschiedene Architekturen für Webanwendungen, die mit Java implementiert werden sollen. Die Antworten auf diese Frage können als Bibliothek verschiedener Webanwendungsdesigns mit ihren Vor- und Nachteilen dienen. Obwohl mir klar ist, dass die Antworten subjektiv sein werden, versuchen wir, so objektiv wie möglich zu sein und die Vor- und Nachteile zu motivieren, die wir auflisten.
Verwenden Sie die von Ihnen bevorzugte Detailebene zur Beschreibung Ihrer Architektur. Damit Ihre Antwort von Wert ist, müssen Sie zumindest die wichtigsten Technologien und Ideen beschreiben, die in der von Ihnen beschriebenen Architektur verwendet werden. Und zu guter Letzt, wann sollten wir Ihre Architektur verwenden?
Ich fange an ...
Überblick über die Architektur
Wir verwenden eine dreistufige Architektur, die auf offenen Standards von Sun wie Java EE, Java Persistence API, Servlet und Java Server Pages basiert.
- Beharrlichkeit
- Unternehmen
- Präsentation
Die möglichen Kommunikationsflüsse zwischen den Schichten werden dargestellt durch:
Persistence <-> Business <-> Presentation
Dies bedeutet beispielsweise, dass die Präsentationsschicht niemals Persistenzoperationen aufruft oder ausführt, sondern immer über die Geschäftsschicht. Diese Architektur soll die Anforderungen einer hochverfügbaren Webanwendung erfüllen.
Beharrlichkeit
Führt CRUD- Persistenzvorgänge zum Erstellen, Lesen, Aktualisieren und Löschen aus . In unserem Fall verwenden wir ( Java Persistence API ) JPA und verwenden derzeit Hibernate als unseren Persistenzanbieter und verwenden dessen EntityManager .
Diese Schicht ist in mehrere Klassen eingeteilt, wobei jede Klasse beschäftigt sich mit einer bestimmten Art von Einheiten (dh Einheiten zu einem Einkaufswagen im Zusammenhang könnten durch eine einzige Persistenz Klasse behandelt werden) und wird verwendet , um ein und nur ein Manager .
Zusätzlich speichert diese Schicht auch JPA - Entitäten , die Dinge sind wie Account
, ShoppingCart
usw.
Unternehmen
Die gesamte Logik, die an die Funktionalität der Webanwendung gebunden ist, befindet sich in dieser Schicht. Diese Funktion kann eine Geldüberweisung für einen Kunden initiieren, der ein Produkt online mit seiner Kreditkarte bezahlen möchte. Es könnte genauso gut sein, einen neuen Benutzer zu erstellen, einen Benutzer zu löschen oder das Ergebnis eines Kampfes in einem webbasierten Spiel zu berechnen.
Diese Ebene ist in mehrere Klassen unterteilt, und jede dieser Klassen wird mit @Stateless
einem SLSB ( Stateless Session Bean ) versehen. Jeder SLSB wird als Manager bezeichnet, und beispielsweise kann ein Manager eine Klasse sein, die wie erwähnt mit Anmerkungen versehen ist AccountManager
.
Wenn AccountManager
CRUD-Operationen ausgeführt werden müssen, werden die entsprechenden Aufrufe an eine Instanz von ausgeführt AccountManagerPersistence
, die eine Klasse in der Persistenzschicht ist. Eine grobe Skizze von zwei Methoden in AccountManager
könnte sein:
...
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
}
Wir verwenden Container-Manager-Transaktionen, damit wir keine eigenen Transaktionsabgrenzungen vornehmen müssen. Was im Grunde genommen unter der Haube passiert, ist, dass wir bei der Eingabe der SLSB-Methode eine Transaktion initiieren und diese unmittelbar vor dem Beenden der Methode festschreiben (oder zurücksetzen). Es ist ein Beispiel für eine Konvention über die Konfiguration, aber wir brauchten bisher nur die Standardeinstellung Erforderlich.
So erklärt das Java EE 5-Lernprogramm von Sun das erforderliche Transaktionsattribut für Enterprise JavaBeans (EJBs):
Wenn der Client innerhalb einer Transaktion ausgeführt wird und die Enterprise-Bean-Methode aufruft, wird die Methode innerhalb der Transaktion des Clients ausgeführt. Wenn der Client keiner Transaktion zugeordnet ist, startet der Container eine neue Transaktion, bevor die Methode ausgeführt wird.
Das Attribut Erforderlich ist das implizite Transaktionsattribut für alle Enterprise-Bean-Methoden, die mit einer vom Container verwalteten Transaktionsabgrenzung ausgeführt werden. Normalerweise legen Sie das Attribut Erforderlich nur fest, wenn Sie ein anderes Transaktionsattribut überschreiben müssen. Da Transaktionsattribute deklarativ sind, können Sie sie später problemlos ändern.
Präsentation
Unsere Präsentationsschicht ist verantwortlich für ... Präsentation! Es ist für die Benutzeroberfläche verantwortlich und zeigt dem Benutzer Informationen an, indem es HTML-Seiten erstellt und Benutzereingaben über GET- und POST-Anforderungen empfängt. Wir verwenden derzeit die alte JSP- Kombination ( Servlet + Java Server Pages ).
Die Schicht ruft Methoden in Managern der Geschäftsschicht auf, um vom Benutzer angeforderte Vorgänge auszuführen und Informationen zu erhalten, die auf der Webseite angezeigt werden sollen. Manchmal handelt es sich bei den von der Geschäftsschicht empfangenen Informationen um weniger komplexe Typen wie String
's und int
egers, manchmal um JPA-Entitäten .
Vor- und Nachteile mit der Architektur
Vorteile
- Wenn wir in dieser Ebene alles haben, was mit einer bestimmten Art der Persistenz zu tun hat, können wir nur von der Verwendung von JPA zu etwas anderem wechseln, ohne etwas in der Business-Ebene neu schreiben zu müssen.
- Es fällt uns leicht, unsere Präsentationsebene in etwas anderes zu tauschen, und es ist wahrscheinlich, dass wir es tun, wenn wir etwas Besseres finden.
- Es ist schön, den EJB-Container Transaktionsgrenzen verwalten zu lassen.
- Die Verwendung von Servlets + JPA ist (zunächst) einfach und die Technologien sind weit verbreitet und auf vielen Servern implementiert.
- Die Verwendung von Java EE soll es uns erleichtern, ein Hochverfügbarkeitssystem mit Lastausgleich und Failover zu erstellen . Beides haben wir das Gefühl, dass wir es haben müssen.
Nachteile
- Mit JPA können Sie häufig verwendete Abfragen als benannte Abfragen speichern, indem Sie die
@NamedQuery
Annotation für die JPA-Entitätsklasse verwenden. Wenn Sie wie in unserer Architektur so viel wie möglich mit der Persistenz in den Persistenzklassen zu tun haben, werden die Stellen verteilt, an denen Sie möglicherweise Abfragen finden, die auch die JPA-Entitäten einschließen. Es wird schwieriger sein, einen Überblick über Persistenzoperationen zu erhalten, und es wird daher schwieriger sein, diese zu warten. - Wir haben JPA-Entitäten als Teil unserer Persistenzschicht. Aber
Account
undShoppingCart
, sind sie nicht wirklich Geschäftsobjekte? Dies geschieht auf diese Weise, da Sie diese Klassen berühren und in Entitäten umwandeln müssen, mit denen JPA umgehen kann. - Die JPA-Entitäten, die auch unsere Geschäftsobjekte sind, werden wie Datenübertragungsobjekte ( DTOs ) erstellt, die auch als Value Objects (VOs) bezeichnet werden. Dies führt zu einem anämischen Domänenmodell, da die Geschäftsobjekte außer Zugriffsmethoden keine eigene Logik haben. Die gesamte Logik wird von unseren Managern in der Geschäftsschicht ausgeführt, was zu einem prozeduraleren Programmierstil führt. Es ist kein gutes objektorientiertes Design, aber vielleicht ist das kein Problem? (Schließlich ist die Objektorientierung nicht das einzige Programmierparadigma, das Ergebnisse geliefert hat.)
- Die Verwendung von EJB und Java EE führt zu einer gewissen Komplexität. Und wir können nicht nur Tomcat verwenden (das Hinzufügen eines EJB-Mikrocontainers ist nicht nur Tomcat).
- Es gibt viele Probleme bei der Verwendung von Servlets + JPA. Verwenden Sie Google, um weitere Informationen zu diesen Problemen zu erhalten.
- Da die Transaktionen beim Verlassen der Business-Schicht geschlossen werden, können keine Informationen von JPA-Entitäten geladen werden, die so konfiguriert sind, dass sie aus der Datenbank geladen werden, wenn sie
fetch=FetchType.LAZY
innerhalb der Präsentationsschicht benötigt (verwendet ) werden. Es wird eine Ausnahme ausgelöst. Bevor wir eine Entität zurückgeben, die diese Art von Feldern enthält, müssen wir sicherstellen, dass wir die entsprechenden Getter aufrufen. Eine andere Möglichkeit besteht darin, Java Persistence Query Language ( JPQL ) zu verwenden und aFETCH JOIN
. Beide Optionen sind jedoch etwas umständlich.
quelle
Antworten:
Ok, ich mache eine (kürzere):
Wir verwenden die Sping-Transaktionsunterstützung und starten Transaktionen beim Betreten der Serviceschicht, die bis zu den DAO-Aufrufen weitergegeben werden. Die Service-Schicht verfügt über die meisten Geschäftsmodellkenntnisse, und die DAOs erledigen relativ einfache CRUD-Arbeiten.
Einige kompliziertere Abfragen werden aus Leistungsgründen von komplizierteren Abfragen im Backend behandelt.
Die Verwendung von Spring hat in unserem Fall den Vorteil, dass wir länder- / sprachabhängige Instanzen haben können, die hinter einer Spring Proxy-Klasse stehen. Basierend auf dem Benutzer in der Sitzung wird beim Tätigen des Anrufs die richtige Länder- / Sprachimplementierung verwendet.
Das Transaktionsmanagement ist nahezu transparent, Rollback bei Laufzeitausnahmen. Wir verwenden so oft wie möglich ungeprüfte Ausnahmen. Früher haben wir geprüfte Ausnahmen gemacht, aber mit der Einführung von Spring sehe ich die Vorteile ungeprüfter Ausnahmen, die Ausnahmen nur dann behandeln, wenn Sie können. Es vermeidet eine Menge Boilerplate "Catch / Rethrow" oder "Throws" Zeug.
Sorry, es ist kürzer als dein Beitrag, hoffe du findest das interessant ...
quelle
Ideale Java-basierte Webentwicklungstechnologien heute.
Webebene:
HTML + CSS + Ajax + JQuery
RESTFul Web Controller / Aktions- / Anforderungsverarbeitungsschicht:
Framework spielen
Geschäftslogik / Serviceschicht:
Verwenden Sie so lange wie möglich reinen Java-Code. Hier kann man Webdienste fusionieren.
XML / JSon-Datentransformationsschicht:
XMLTool (Suche nach Google Code), JSoup, Google GSon, XStream, JOOX (Suche nach Google Code)
Persistenzschicht:
CRUD: JPA oder SienaProject oder QueryDSL / Komplexe Abfragen: JOOQ, QueryDSL
quelle
Hier sind meine 5 Cent
Präsentation
Android, Angular.JS WebClient, OAUTHv2
API
REST, Jersey (JAX-RS), Jackson (JSON-De- / Serialisierung), DTO-Objekte (anders als Geschäftslogikmodelle)
Geschäftslogik
Feder für DI- und Event-Handling. DDD-artiger Ansatz von Modellobjekten. Länger laufende Jobs werden mit SQS in Worker-Modulen ausgelagert.
DAO
Repository-Modell mit Spring JDBC-Vorlagen zum Speichern von Entitäten. Redis (JEDIS) für Bestenlisten unter Verwendung geordneter Listen. Memcache für Token Store.
Datenbank
MySQL, Memcached, Redis
quelle
Was wir in unserem Projekt verfolgt haben, ist:
Front-End-Technologie
API
Geschäftslogik
FRÜHLINGSDATEN
FRÜHLINGSDATEN MongoDB
Datenbank
Server (zum Zwischenspeichern)
quelle
Wir verwenden immer noch den üblichen Struts-Spring-Hibernate-Stack.
Für zukünftige Apps untersuchen wir Spring Web Flow + Spring MVC + Hibernate oder Spring + Hibernate + Web Services mit Flex-Frontend.
Ein besonderes Merkmal unserer Architektur ist die Modularisierung. Wir haben eine Reihe von Modulen, von denen einige mit 3 bis maximal 30 Tabellen in der Datenbank beginnen. Die meisten Module bestehen aus Business- und Webprojekten. Das Geschäftsprojekt enthält die Geschäfts- und Persistenzlogik, während das Web die Präsentationslogik enthält.
Auf logischer Ebene gibt es drei Ebenen: Business, Persistence und Presentation.
Abhängigkeiten: Die
Präsentation hängt vom Geschäft und der Persistenz ab.
Die Beharrlichkeit hängt vom Geschäft ab.
Das Geschäft hängt nicht von anderen Schichten ab.
Die meisten Geschäftsprojekte verfügen über drei Arten von Schnittstellen (Hinweis: keine grafische Benutzeroberfläche, sondern eine programmatische Java-Schnittstellenschicht).
Oft erweitert 1 2. Auf diese Weise ist es einfach, eine Implementierung eines Moduls durch eine andere zu ersetzen. Dies hilft uns, uns an verschiedene Kunden anzupassen und einfacher zu integrieren. Einige Kunden kaufen nur bestimmte Module und wir müssen bereits vorhandene Funktionen integrieren. Da Schnittstelle und Implementierungsschicht getrennt sind, ist es einfach, die Implementierung von Ad-Hock-Modulen für diesen bestimmten Client einzuführen, ohne die abhängigen Module zu beeinflussen. Und Spring Framework macht es einfach, verschiedene Implementierungen einzufügen.
Unsere Geschäftsschicht basiert auf POJOs. Eine Tendenz, die ich beobachte, ist, dass diese POJOs DTOs ähneln. Wir leiden unter einem anämischen Domänenmodell . Ich bin mir nicht ganz sicher, warum dies geschieht, aber es kann an der Einfachheit der Problemdomäne vieler unserer Module liegen, der größte Teil der Arbeit ist CRUD oder an Entwicklern, die Logik lieber woanders platzieren.
quelle
Hier ist eine weitere Webarchitektur, an der ich gearbeitet habe:
Präsentationsstufe:
Mobiles Web (HTML5 / CSS3 / Responsive Design)
Feder-REST-Controller (Kann zu JAX-RS wechseln)
Business Service Tier:
Spring @Service (Kann zu Stateless EJB wechseln)
Datenzugriffsebene:
Spring @Repository (Kann zu Stateless EJB wechseln)
Ressourcenebene:
JPA-Entitäten (Hibernate) (können zu jedem ORM geändert werden)
Weitere Informationen zu dem Buch, das dieser Architektur folgt, finden Sie hier .
quelle
IMHO haben die meisten von uns einen gemeinsamen Nenner. Zumindest im Backend haben wir eine Art IOC / DI-Container und ein Persistenz-Framework. Persönlich benutze ich dafür Guice und Mybatis. Die Unterschiede bestehen darin, wie wir die Ansichts- / UI- / Präsentationsschicht implementieren. Hier gibt es zwei Hauptoptionen (möglicherweise mehr). Aktionsbasiert (URLs, die Controllern zugeordnet sind) und komponentenbasiert. Derzeit verwende ich eine komponentenbasierte Präsentationsschicht (mit Wicket). Es ahmt perfekt eine Desktop-Umgebung nach, in der ich Komponenten und Ereignisse im Gegensatz zu URLs und Controllern verwende. Ich suche derzeit nach einem Grund, warum ich auf diese URL-Controller-Architektur migrieren sollte (so bin ich auf diese Seite gekommen). Warum der Hype um RESTful- und Stateless-Architekturen?
Um diese Frage kurz zu beantworten: Ich schreibe Stateful-Webanwendungen mit einem komponentenorientierten Framework über den Guice-IOC-Container und speichere Daten mit Mybatis in einer relationalen Datenbank.
quelle
Ein bisschen anders, und ich würde hier eine modularere Java-Architektur beanspruchen. Wir haben:
Darüber hinaus verfügen wir über die gemeinsam genutzten Bibliotheksmodule, die für alle Dienste ein gemeinsamer Funktionsanbieter sind.
Die Verwendung verschiedener Schichten ermöglicht uns eine vollständige Entkopplung und die von uns benötigte Modularität. Wir können auch die Leistung von Java EE und Spring voll ausnutzen. Nichts hindert uns daran, JSF beispielsweise für das Frontend bei Bedarf zu verwenden.
Im Vergleich zur Beispielarchitektur von OP kann dies meiner Meinung nach mit vier statt drei Hauptschichten beschrieben werden, wenn auch mit einer Wendung.
quelle
Ich habe an Projekten gearbeitet, die dieses starre Manager-Muster verwenden. Historisch gesehen war ich ein großer Befürworter der starren Hierarchie, in der alles in eine ordentliche Schachtel passte. Im Laufe meiner Karriere finde ich es in vielen Fällen erzwungen. Ich glaube, dass eine agilere Einstellung zum Anwendungsdesign zu einem besseren Produkt führt. Was ich damit meine, eine Reihe von Klassen zu erstellen, die das vorliegende Problem lösen. Anstatt zu sagen "Haben Sie einen Manager für dies und das gebaut?"
Das aktuelle Projekt, an dem ich arbeite, ist eine Web-App mit einer Kombination aus Spring MVC- und RestEasy JSON / Ajax-Aufrufen. Auf der Serverseite, die in unsere Controller eingebettet ist, befindet sich eine sinnvolle fassadenbasierte Datenebene mit JPA / Hibernate für den direkten Datenbankzugriff, einige EJB-Zugriffe und einige SOAP-basierte Webdienstaufrufe. All dies ist ein benutzerdefinierter Java-Controller-Code, der festlegt, was als JSON serialisiert und an den Client zurückgegeben werden soll.
Wir verbringen fast keine Zeit damit, ein einheitliches Muster zu erstellen, sondern entscheiden uns für die Idee "Schlimmer ist besser" der Unix-Designphilosophie. Da es viel besser ist, außerhalb der Linien zu färben und schnell etwas Sinnvolles zu bauen, als etwas zu bauen, das einer Reihe strenger Designmandate entspricht.
quelle
Die Komponenten in der Webanwendungsarchitektur umfassen:
1: Browser: Client-Interaktion
2: Internet
3: Webserver
4: Anwendungsserver
5: Datenbankserver
6: Daten
quelle