¡Compartamos arquitecturas de aplicaciones web basadas en Java!
Existen muchas arquitecturas diferentes para aplicaciones web que se implementarán utilizando Java. Las respuestas a esta pregunta pueden servir como una biblioteca de varios diseños de aplicaciones web con sus ventajas y desventajas. Si bien me doy cuenta de que las respuestas serán subjetivas, tratemos de ser lo más objetivos posible y motivar los pros y los contras que enumeramos.
Use el nivel de detalle que prefiera para describir su arquitectura. Para que su respuesta tenga algún valor, al menos tendrá que describir las principales tecnologías e ideas utilizadas en la arquitectura que describe. Y por último, pero no menos importante, ¿ cuándo debemos usar su arquitectura?
Yo empezare...
Resumen de la arquitectura
Utilizamos una arquitectura de 3 niveles basada en estándares abiertos de Sun como Java EE, Java Persistence API, Servlet y Java Server Pages.
- Persistencia
- Negocio
- Presentación
Los posibles flujos de comunicación entre las capas están representados por:
Persistence <-> Business <-> Presentation
Lo que, por ejemplo, significa que la capa de presentación nunca llama o realiza operaciones de persistencia, siempre lo hace a través de la capa empresarial. Esta arquitectura está destinada a satisfacer las demandas de una aplicación web de alta disponibilidad.
Persistencia
Realiza operaciones de persistencia de creación, lectura, actualización y eliminación ( CRUD ). En nuestro caso estamos utilizando JPA ( Java Persistence API ) y actualmente utilizamos Hibernate como nuestro proveedor de persistencia y utilizamos su EntityManager .
Esta capa se divide en varias clases, donde cada clase trata con un cierto tipo de entidades (es decir, las entidades relacionadas con un carrito de compras pueden ser manejadas por una sola clase de persistencia) y es utilizada por un solo administrador .
Además, esta capa también almacena entidades JPA que son cosas como Account
, ShoppingCart
etc.
Negocio
Toda la lógica que está vinculada a la funcionalidad de la aplicación web se encuentra en esta capa. Esta funcionalidad podría iniciar una transferencia de dinero para un cliente que desea pagar un producto en línea usando su tarjeta de crédito. También podría crear un nuevo usuario, eliminar un usuario o calcular el resultado de una batalla en un juego basado en la web.
Esta capa se divide en varias clases y cada una de estas clases se anota @Stateless
para convertirse en un bean de sesión sin estado (SLSB). Cada SLSB se denomina administrador y, por ejemplo, un administrador podría ser una clase anotada como se mencionó AccountManager
.
Cuando AccountManager
necesita realizar operaciones CRUD, realiza las llamadas apropiadas a una instancia de AccountManagerPersistence
, que es una clase en la capa de persistencia. Un bosquejo de dos métodos AccountManager
podría ser:
...
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
}
Utilizamos las transacciones del administrador de contenedores para no tener que hacer la demarcación de las transacciones. Lo que básicamente sucede debajo del capó es que iniciamos una transacción al ingresar el método SLSB y lo confirmamos (o revertimos) inmediatamente antes de salir del método. Es un ejemplo de convención sobre la configuración, pero aún no hemos necesitado nada más que el valor predeterminado, Obligatorio.
Así es como el Tutorial Java EE 5 de Sun explica el atributo de transacción requerido para Enterprise JavaBeans (EJB's):
Si el cliente se ejecuta dentro de una transacción e invoca el método del bean Enterprise, el método se ejecuta dentro de la transacción del cliente. Si el cliente no está asociado con una transacción, el contenedor inicia una nueva transacción antes de ejecutar el método.
El atributo Requerido es el atributo de transacción implícito para todos los métodos de Enterprise Bean que se ejecutan con demarcación de transacciones gestionadas por contenedor. Por lo general, no establece el atributo Requerido a menos que necesite anular otro atributo de transacción. Debido a que los atributos de transacción son declarativos, puede cambiarlos fácilmente más adelante.
Presentación
Nuestra capa de presentación está a cargo de ... ¡presentación! Es responsable de la interfaz de usuario y muestra información al usuario mediante la creación de páginas HTML y la recepción de la entrada del usuario a través de solicitudes GET y POST. Actualmente estamos utilizando la antigua combinación Servlet 's + Java Server Pages ( JSP ).
La capa llama a los métodos de los administradores de la capa empresarial para realizar operaciones solicitadas por el usuario y recibir información para mostrar en la página web. A veces, la información recibida de la capa empresarial son tipos menos complejos como String
's y int
egers, y otras veces entidades JPA .
Pros y contras con la arquitectura.
Pros
- Tener todo lo relacionado con una forma específica de persistencia en esta capa solo significa que podemos cambiar de usar JPA a otra cosa, sin tener que volver a escribir nada en la capa empresarial.
- Es fácil para nosotros intercambiar nuestra capa de presentación en otra cosa, y es probable que lo hagamos si encontramos algo mejor.
- Dejar que el contenedor EJB administre los límites de las transacciones es bueno.
- Usar Servlet's + JPA es fácil (para empezar) y las tecnologías son ampliamente utilizadas e implementadas en muchos servidores.
- Se supone que el uso de Java EE nos facilita la creación de un sistema de alta disponibilidad con equilibrio de carga y conmutación por error . Los cuales sentimos que debemos tener.
Contras
- Con JPA puede almacenar consultas de uso frecuente como consultas con nombre utilizando la
@NamedQuery
anotación en la clase de entidad JPA. Si tiene tanto como sea posible relacionado con la persistencia en las clases de persistencia, como en nuestra arquitectura, esto extenderá las ubicaciones donde puede encontrar consultas para incluir también las entidades JPA. Será más difícil tener una visión general de las operaciones de persistencia y, por lo tanto, más difícil de mantener. - Tenemos entidades JPA como parte de nuestra capa de persistencia. Pero
Account
yShoppingCart
, ¿no son realmente objetos comerciales? Se hace de esta manera, ya que debe tocar estas clases y convertirlas en entidades que JPA sabe cómo manejar. - Las entidades JPA, que también son nuestros objetos comerciales, se crean como objetos de transferencia de datos ( DTO ), también conocidos como objetos de valor (VO). Esto da como resultado un modelo de dominio anémico ya que los objetos de negocio no tienen lógica propia, excepto los métodos de acceso. Nuestros gerentes realizan toda la lógica en la capa empresarial, lo que da como resultado un estilo de programación más procesal. No es un buen diseño orientado a objetos, pero ¿tal vez eso no sea un problema? (Después de todo, la orientación a objetos no es el único paradigma de programación que ha arrojado resultados).
- El uso de EJB y Java EE introduce un poco de complejidad. Y no podemos usar puramente Tomcat (agregar un microcontenedor EJB no es puramente Tomcat).
- Hay muchos problemas con el uso de Servlet's + JPA. Use Google para obtener más información sobre estos problemas.
- Como las transacciones se cierran al salir de la capa empresarial, no podemos cargar ninguna información de entidades JPA que esté configurada para cargarse desde la base de datos cuando sea necesario (usando
fetch=FetchType.LAZY
) desde el interior de la capa de presentación. Activará una excepción. Antes de devolver una entidad que contenga este tipo de campos, debemos asegurarnos de llamar a los captadores relevantes. Otra opción es usar Java Persistence Query Language ( JPQL ) y hacer unFETCH JOIN
. Sin embargo, ambas opciones son un poco engorrosas.