¡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.
fuente
Respuestas:
Ok, haré uno (más corto):
Utilizamos el soporte de transacciones Sping e iniciamos transacciones al ingresar a la capa de servicio, propagándonos a las llamadas de DAO. La capa de servicio tiene el mayor conocimiento del modelo de negocio, y los DAO realizan un trabajo CRUD relativamente simple.
Algunas consultas más complicadas se manejan mediante consultas más complicadas en el backend por razones de rendimiento.
Las ventajas de usar Spring en nuestro caso es que podemos tener instancias dependientes del país / idioma, que están detrás de una clase Spring Proxy. Según el usuario en la sesión, se utiliza la implementación correcta de país / idioma al hacer una llamada.
La gestión de transacciones es casi transparente, revierte las excepciones de tiempo de ejecución. Utilizamos excepciones no marcadas tanto como sea posible. Solíamos hacer excepciones marcadas, pero con la introducción de Spring veo los beneficios de las excepciones no marcadas, solo manejando las excepciones cuando puedes. Evita muchas cosas repetitivas de "atrapar / volver a lanzar" o "arrojar".
Lo siento, es más corto que tu publicación, espero que encuentres esto interesante ...
fuente
Tecnologías de desarrollo web basadas en Java ideales hoy.
Capa web:
HTML + CSS + Ajax + JQuery
REST Controlador web / acción / capa de procesamiento de solicitudes:
Marco de juego
Lógica empresarial / Capa de servicio:
Use Pure Java Code el mayor tiempo posible. Uno puede hacer fusión de servicios web aquí.
Capa de transformación de datos XML / JSon:
XMLTool (Buscar en el código de Google), JSoup, Google GSon, XStream, JOOX (Buscar en el código de Google)
Capa de persistencia:
CRUD: JPA o SienaProject o QueryDSL / Consultas complejas: JOOQ, QueryDSL
fuente
Aquí están mis 5 centavos
Presentación
Android, Angular.JS WebClient, OAUTHv2
API
REST, Jersey (JAX-RS), Jackson (des / serialización JSON), objetos DTO (diferentes de los modelos de lógica de negocios)
Lógica de negocios
Primavera para DI y manejo de eventos. Enfoque DDD-ish de objetos modelo. Los trabajos de ejecución más larga se descargan con SQS en los módulos de trabajo.
DAO
Modelo de repositorio con plantillas Spring JDBC para almacenar entidades. Redis (JEDIS) para tablas de clasificación, utilizando listas ordenadas. Memcache para Token Store.
Base de datos
MySQL, Memcached, Redis
fuente
Lo que hemos seguido en nuestro proyecto es:
Tecnología frontal
API
Lógica de negocios
DATOS DE PRIMAVERA
Datos de PRIMAVERA MongoDB
Base de datos
Servidor (para el almacenamiento en caché)
fuente
Todavía estamos usando la pila habitual Struts-Spring-Hibernate.
Para aplicaciones futuras, estamos analizando Spring Web Flow + Spring MVC + Hibernate o Spring + Hibernate + Web Services con Flex front end.
Una característica distintiva de nuestra arquitectura es la modularización. Tenemos varios módulos, algunos comenzando con 3 hasta un máximo de 30 tablas en la base de datos. La mayoría de los módulos consisten en negocios y proyectos web. El proyecto empresarial tiene lógica empresarial y de persistencia, mientras que la web tiene lógica de presentación.
A nivel lógico, hay tres capas: negocios, persistencia y presentación.
Dependencias: la
presentación depende de los negocios y la persistencia.
La persistencia depende de los negocios.
Los negocios no dependen de otras capas.
La mayoría de los proyectos empresariales tienen tres tipos de interfaces (nota: no GUI, es una capa de interfaz Java programática).
A menudo, 1 se extiende 2. De esta manera, es fácil reemplazar una implementación de módulo por otra. Esto nos ayuda a adoptar diferentes clientes e integrarnos más fácilmente. Algunos clientes comprarán solo ciertos módulos y necesitamos integrar la funcionalidad que ya tienen. Dado que la interfaz y la capa de implementación están separadas, es fácil implementar la implementación del módulo ad-hock para ese cliente específico sin afectar los módulos dependientes. Y Spring Framework facilita la inyección de diferentes implementaciones.
Nuestra capa empresarial se basa en POJO. Una tendencia que estoy observando es que estos POJO se parecen a los DTO. Sufrimos de modelo de dominio anémico . No estoy muy seguro de por qué sucede esto, pero puede deberse a la simplicidad del dominio del problema de muchos de nuestros módulos, la mayor parte del trabajo es CRUD o debido a que los desarrolladores prefieren colocar la lógica en otro lugar.
fuente
Aquí hay una arquitectura web más en la que he trabajado:
Nivel de presentación:
Web móvil (HTML5 / CSS3 / diseño receptivo)
Controladores Spring REST (pueden cambiar a JAX-RS)
Nivel de servicio comercial:
Spring @Service (puede cambiar a EJB sin estado)
Nivel de acceso a datos:
Spring @Repository (puede cambiar a EJB sin estado)
Nivel de recursos:
Entidades de hibernación (JPA) (pueden cambiar a cualquier ORM)
Puede encontrar más información sobre el libro que sigue esta arquitectura aquí .
fuente
En mi humilde opinión, la mayoría de nosotros tenemos un denominador común. Al menos en el back-end, tenemos alguna forma de contenedor IOC / DI y un marco de persistencia. Personalmente uso Guice y Mybatis para esto. Las diferencias están en cómo implementamos la capa de vista / IU / presentación. Aquí hay 2 opciones principales (puede haber más). Basado en acciones (URL asignadas a controladores) y en componentes. Actualmente estoy usando la capa de presentación basada en componentes (usando wicket). Imita perfectamente un entorno de escritorio donde utilizo componentes y eventos en lugar de URL y controladores. Actualmente estoy buscando una razón por la que debería migrar a este tipo de arquitectura de controlador de URL (así es como terminé en esta página). Por qué la exageración sobre las arquitecturas RESTful y Stateless.
Para responder a esta pregunta en resumen: escribo aplicaciones web con estado utilizando un marco orientado a componentes en la parte superior del contenedor Guice IOC y pongo datos en una base de datos relacional usando Mybatis.
fuente
Un poco diferente, y reclamaría más arquitectura modular de Java aquí. Tenemos:
Además de lo anterior, tenemos los módulos de biblioteca compartida, que es un proveedor de funcionalidad común para todos los dispositivos.
El uso de diferentes capas nos permite un desacoplamiento completo y la modularidad que necesitamos. También podemos utilizar plenamente el poder de Java EE y Spring. Nada nos impide usar JSF, por ejemplo, para el front end si es necesario.
En comparación con la arquitectura de ejemplo de OP, creo que esto se puede describir como tener cuatro capas principales en lugar de tres, aunque con un giro.
fuente
He trabajado en proyectos que usan ese patrón rígido de administrador. Históricamente, fui un gran defensor de la rígida jerarquía donde todo encajaba en una caja ordenada. A medida que avanzo en mi carrera, me veo forzado en muchos casos. Creo que adoptar una mentalidad más ágil hacia el diseño de aplicaciones conduce a un mejor producto. Lo que quiero decir con esto es crear un conjunto de clases que resuelvan el problema en cuestión. En lugar de decir "¿Construiste un gerente para esto y aquello?"
El proyecto actual en el que estoy trabajando es una aplicación web con una combinación de llamadas Spring MVC y RestEasy JSON / Ajax. En el lado del servidor incrustado en nuestros controladores hay un nivel de datos basado en fachada sensible con JPA / Hibernate para acceso directo a la base de datos, algunos accesos EJB y algunas llamadas de servicio web basadas en SOAP. Unir todo esto es un código de controlador java personalizado que determina qué serializar como JSON y devolver al cliente.
Casi no pasamos tiempo intentando crear un patrón unificado, sino que optamos por adoptar la idea "Peor es mejor" de la filosofía de diseño de Unix. Siendo que es mucho mejor colorear fuera de las líneas y construir algo sensible, más rápido que construir algo que se adhiera a un montón de estrictos mandatos de diseño.
fuente
Los componentes en arquitectura de aplicaciones web incluyen:
1: Navegador: interacción del cliente
2: Internet
3: servidor web
4: Servidor de aplicaciones
5: Servidor de base de datos
6: datos
fuente