Condividiamo architetture di applicazioni Web basate su Java!
Esistono molte architetture diverse per le applicazioni Web che devono essere implementate utilizzando Java. Le risposte a questa domanda possono fungere da libreria di vari progetti di applicazioni Web con i loro pro e contro. Mentre mi rendo conto che le risposte saranno soggettive, proviamo ad essere il più oggettivi possibile e motivare i pro ei contro che elenchiamo.
Usa il livello di dettaglio che preferisci per descrivere la tua architettura. Affinché la tua risposta abbia valore, dovrai almeno descrivere le principali tecnologie e idee utilizzate nell'architettura che descrivi. E, ultimo ma non meno importante, quando dovremmo usare la tua architettura?
Inizierò...
Panoramica dell'architettura
Utilizziamo un'architettura a 3 livelli basata su standard aperti di Sun come Java EE, Java Persistence API, Servlet e Java Server Pages.
- Persistenza
- Attività commerciale
- Presentazione
I possibili flussi di comunicazione tra i livelli sono rappresentati da:
Persistence <-> Business <-> Presentation
Che, ad esempio, significa che il livello di presentazione non chiama o esegue mai operazioni di persistenza, lo fa sempre attraverso il livello aziendale. Questa architettura è destinata a soddisfare le esigenze di un'applicazione Web ad alta disponibilità.
Persistenza
Esegue operazioni di persistenza di creazione, lettura, aggiornamento ed eliminazione ( CRUD ). Nel nostro caso utilizziamo JPA ( Java Persistence API ) e attualmente utilizziamo Hibernate come nostro provider di persistenza e utilizziamo EntityManager .
Questo livello è diviso in più classi, in cui ogni classe si occupa di un certo tipo di entità (ovvero le entità correlate a un carrello della spesa potrebbero essere gestite da una singola classe di persistenza) ed è utilizzata da un solo gestore .
Inoltre questo strato memorizza anche entità JPA che sono cose come Account, ShoppingCartecc.
Attività commerciale
Tutta la logica collegata alla funzionalità dell'applicazione Web si trova in questo livello. Questa funzionalità potrebbe essere un trasferimento di denaro per un cliente che desidera pagare un prodotto online utilizzando la sua carta di credito. Potrebbe anche essere la creazione di un nuovo utente, l'eliminazione di un utente o il calcolo del risultato di una battaglia in un gioco basato sul Web.
Questo livello è diviso in più classi e ciascuna di queste classi viene annotata @Statelessper diventare un bean di sessione stateless (SLSB). Ogni SLSB è chiamato manager e per esempio un manager può essere una classe annotata come detto chiamato AccountManager.
Quando è AccountManagernecessario eseguire operazioni CRUD, effettua le chiamate appropriate a un'istanza di AccountManagerPersistence, che è una classe nel livello di persistenza. Uno schizzo approssimativo di due metodi AccountManagerpotrebbe essere:
...
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
}
Usiamo le transazioni del gestore di container in modo da non dover fare la demarcazione delle transazioni di noi stessi. Ciò che sostanzialmente accade sotto il cofano è che iniziamo una transazione quando si inserisce il metodo SLSB e lo commettiamo (o eseguiamo il rollback) immediatamente prima di uscire dal metodo. È un esempio di convenzione sulla configurazione, ma non abbiamo ancora avuto bisogno di altro che predefinito, Richiesto.
Ecco come il tutorial Java EE 5 di Sun spiega l' attributo Transaction richiesto per Enterprise JavaBeans (EJB):
Se il client è in esecuzione all'interno di una transazione e invoca il metodo del bean enterprise, il metodo viene eseguito all'interno della transazione del client. Se il client non è associato a una transazione, il contenitore avvia una nuova transazione prima di eseguire il metodo.
L'attributo Richiesto è l'attributo di transazione implicita per tutti i metodi bean enterprise in esecuzione con demarcazione delle transazioni gestite dal contenitore. In genere non si imposta l'attributo Richiesto a meno che non sia necessario sovrascrivere un altro attributo di transazione. Poiché gli attributi di transazione sono dichiarativi, è possibile modificarli facilmente in un secondo momento.
Presentazione
Il nostro livello di presentazione è responsabile di ... presentazione! È responsabile dell'interfaccia utente e mostra informazioni all'utente costruendo pagine HTML e ricevendo l'input dell'utente tramite richieste GET e POST. Attualmente stiamo utilizzando la vecchia combinazione Servlet di + Java Server Pages ( JSP ).
Il livello chiama i metodi nei gestori del livello aziendale per eseguire le operazioni richieste dall'utente e per ricevere informazioni da mostrare nella pagina Web. A volte le informazioni ricevute dal livello di business sono i tipi meno complesse come String's e intEgers, e in altri momenti entità JPA .
Pro e contro con l'architettura
Professionisti
- Avere tutto ciò che riguarda un modo specifico di perseverare in questo livello significa solo che possiamo passare dall'uso dell'APP a qualcos'altro, senza dover riscrivere nulla nel livello aziendale.
- È facile per noi scambiare il nostro livello di presentazione in qualcos'altro, ed è probabile che lo faremo se troviamo qualcosa di meglio.
- Consentire al contenitore EJB di gestire i limiti delle transazioni è utile.
- L'uso di + JPA di Servlet è facile (per cominciare) e le tecnologie sono ampiamente utilizzate e implementate in molti server.
- L'uso di Java EE dovrebbe semplificarci la creazione di un sistema ad alta disponibilità con bilanciamento del carico e failover . Entrambi sentiamo di dover avere.
Contro
- Utilizzando JPA è possibile archiviare query utilizzate spesso come query denominate utilizzando l'
@NamedQueryannotazione sulla classe entità JPA. Se hai il più possibile correlato alla persistenza nelle classi di persistenza, come nella nostra architettura, questo spiegherà le posizioni in cui potresti trovare query per includere anche le entità JPA. Sarà più difficile dare una panoramica delle operazioni di persistenza e quindi più difficile da mantenere. - Abbiamo entità JPA come parte del nostro livello di persistenza. Ma
AccounteShoppingCart, non sono in realtà oggetti di business? È fatto in questo modo poiché devi toccare queste classi e trasformarle in entità che JPA sa come gestire. - Le entità JPA, che sono anche i nostri oggetti business, sono create come Data Transfer Objects ( DTO ), noto anche come Value Objects (VO). Ciò si traduce in un modello di dominio anemico poiché gli oggetti business non hanno una logica propria tranne i metodi di accesso. Tutta la logica viene eseguita dai nostri manager nel livello aziendale, che si traduce in uno stile di programmazione più procedurale. Non è un buon design orientato agli oggetti, ma forse non è un problema? (Dopo tutto l'orientamento agli oggetti non è l'unico paradigma di programmazione che ha prodotto risultati.)
- L'uso di EJB e Java EE introduce un po 'di complessità. E non possiamo usare puramente Tomcat (l'aggiunta di un micro-contenitore EJB non è puramente Tomcat).
- Ci sono molti problemi con l'utilizzo di Servlet + JPA. Utilizza Google per ulteriori informazioni su questi problemi.
- Poiché le transazioni vengono chiuse all'uscita dal livello aziendale, non è possibile caricare alcuna informazione dalle entità JPA che è configurata per essere caricata dal database quando è necessario (utilizzando
fetch=FetchType.LAZY) dall'interno del livello presentazione. Attiverà un'eccezione. Prima di restituire un'entità che contiene questo tipo di campi, dobbiamo essere sicuri di chiamare i getter pertinenti. Un'altra opzione è utilizzare Java Persistence Query Language ( JPQL ) e fare unFETCH JOIN. Tuttavia entrambe queste opzioni sono un po 'ingombranti.