0% encontró este documento útil (0 votos)
0 vistas183 páginas

Java Microservices Parte1

microservicios

Cargado por

Peter Cocho
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
0 vistas183 páginas

Java Microservices Parte1

microservicios

Cargado por

Peter Cocho
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

Microservicios y

contenedores Java
en la Nube
Con Spring Boot, Kafka,
PostgreSQL, Kubernetes,
Helm, Terraform y AWS
EKS

Binildas A. Christudas
Microservicios y contenedores Java en la nube: con Spring Boot, Kafka,
PostgreSQL, Kubernetes, Helm, Terraform y AWS EKS
Binildas A. ChristudasNBCRA 45,
ChristbinThiruvananthapuram,
Kerala, India

ISBN-13 (pbk): 979-8-8688-0554-7 ISBN-13 (electrónico): 979-8-8688-0555-4


[Link]

Copyright © 2024 por Binildas A. Christudas


Esta obra está sujeta a derechos de autor. Todos los derechos están reservados por el Editor, ya sea
que se trate de la totalidad o parte del material, específicamente los derechos de traducción,
reimpresión, reutilización de ilustraciones, recitación, emisión, reproducción en microfilms o de
cualquier otra forma física, y transmisión o almacenamiento y recuperación de información,
adaptación electrónica, software informático o mediante metodologías similares o disimilares ya
conocidas o desarrolladas posteriormente. En este libro pueden aparecer nombres registrados,
logotipos e imágenes. En lugar de usar un símbolo de marca en cada vez que aparece un nombre,
logotipo o imagen registrada, usamos los nombres, logotipos e imágenes solo de forma editorial y en
beneficio del titular de la marca, sin intención de infringir la marca. El uso en esta publicación de
nombres comerciales, marcas comerciales, marcas de servicio y términos similares, aunque no se
identifiquen como tales, no debe tomarse como una expresión de opinión sobre si están o no sujetos a
derechos de propiedad. Aunque se considera que los consejos e información de este libro son
verdaderos y precisos en la fecha de publicación, ni los autores, ni los editores, ni el editor pueden
aceptar responsabilidad legal por cualquier error u omisión que pueda cometerse. El editor no ofrece
ninguna garantía, expresa o implícita, respecto al material aquí contenido.

Director General, Apress Media LLC: Welmoed SpahrEditor de adquisiciones: James Robinson-Prior
& Divya ModiEditor de desarrollo: James MarkhamEditor coordinador: Gryffin WinklerEditor de
estilo: Kezia EndsleyPortada diseñada por eStudioCalamarImagen de portada por
[Link] al sector editorial mundial por Apress Media, LLC, 1 New York Plaza,
Nueva York, NY10004, [Link]. Teléfono 1-800-SPRINGER, fax (201) 348-4505, correo electrónico
orders-ny@[Link] o visite [Link]. Apress Media, LLC es una LLC de
California y el único miembro (propietario) es Springer Science + Business Media Finance Inc
(SSBM Finance Inc). SSBM FinanceInc es una corporación de Delaware. Para información sobre
traducciones, por favor envíe un correo electrónico a booktranslations@[Link]; Para
reimpresión, tapa blanda o derechos de audio, por favor envíe un correo electrónico
bookpermissions@[Link]. Los títulos de Apress pueden adquirirse al por mayor para uso
académico, corporativo o promocional. También hay versiones y licencias disponibles para la
mayoría de los títulos. Para más información, consulta nuestra página web de Ventas al Por Mayor de
Libros Impresos y eBooks en [Link] código fuente u otro material
suplementario referenciado por el autor en este libro está disponible para los lectores en GitHub
([Link] Para más información detallada, por favor visite
[Link] desechar este producto, por favor recicle el papel
A Sowmya Hubert, Ann S. Binil y Ria S. Binil
Índice
Acerca del autor xxiAcerca del revisor técnico
xxiiiAgradecimientos xxvIntroducción xxvii

Capítulo 1: Microservicios para la Enterprise 1


Paradigmas de Arquitectura de Computación 2
Computación Centralizada 2Computación Distribuida 4Computación
Descentralizada 7Sistemas de Software Finalmente Consistentes 9

Consistencia Atómica 9Consistencia Eventual 11Sistemas


Eventualmente Consistentes y Descentralizados 13 Granularidad del
Servicio 15

Monolito 15Macroservicio 16Mini Servicio 16Microservicios 17La


metáfora de la arquitectura hexagonal 18

Arquitectura en capas 19La arquitectura de puertos y adaptadores


19

v
Tabla de ConTenTs

Arquitectura Hexagonal 22Metamodelo de Microservicios 22Tu


primer microservicio Java 25

Spring Boot 26Diseña tu primer microservicio hexagonal


26Organización de código 28Entendiendo el Código 30Construye y
ejecuta el código 35Prueba el microservicio usando UI 38Prueba el
microservicio usando cURL 43Resumen 43

Capítulo 2: Microservicios más prácticos 45


Microservicios usando MongoDB y RestTemplate 46
Diseñar el microservicio 46Código Organización 47Entender el
Código 50Construir y ejecutar el microservicio 57Probar el
Microservicios 60Microservicios Usando Spring Cloud 61

Diseñar los microservicios 61Entender el código 62Construir y


ejecutar el microservicio 65Probar los microservicios 67HATEOAS y
HAL 67

HATEOAS explicado 68HAL explicado 69

vi
Tabla de ConTenTs

Microservicios que utilizan HATEAOS y HAL 70


Diseñar el Microservicios 70Organización del Código 71Entender el
Código 72Construir y ejecutar el microservicio 75Probar el
microservicio 77Resumen 78

Capítulo 3: Cebolla y arquitectura hexagonal en la práctica 81


Microservicios usando PostgreSQL y RestTemplate 82
Diseña el Microservicio 82Entendiendo el código 83Construye y
ejecuta el Microservicio 92Probando el Microservicio
95Microservicios usando MongoDB y Repositorio Crud 96

Arquitectura hexagonal revisitada 97Entendiendo el código


97Construyendo y ejecutando el microservicio 100Probando los
microservicios 102The Onion Arquitectura 104

Diseño de la Arquitectura Onion 104Onion vs Arquitectura Hexagonal


106GraphQL 107

Ejemplo 108 de microservicio explicado en GraphQL Arquitectura


107Onion
Diseño de cebolla para la Microservice 109Code Organization 110

vii
Tabla de ConTenTs

Entendiendo el código 111Construye y ejecuta el microservicio


123Probando el microservicio 125Resumen 132

Capítulo 4: Microservicios orientados a mensajes 133


Características de los Microservicios 134
Los microservicios son autónomos 134 Los microservicios son
evolutivos 135 La analogía del panal 137 Asincrónico, sigue siendo
petición-respuesta 137

Solicitud asíncrona 137Solicitud-Respuesta asíncrona


138Sincronización sobre microservicios asíncronos 140

Diseñar microservicios sobre canal asincrónico 140Entender el


código 141Construir y ejecutar el microservicio 151Probar el
microservicio 153SEDA y microservicios 154

Arquitectura SEDA 154 Arquitectura de microservicios como red de


etapas 156 HTTP asíncrono sincronizado sobre microservicios
asíncronos 157

Entendiendo el código 157Construye y ejecuta el microservicio


162Probando el microservicio 165Resumen 168

viii
Tabla de ConTenTs

Capítulo 5: Integración de microservicios en la práctica 171


Escalabilidad de microservicios en la nube 172
Escalabilidad vertical 172Escalabilidad horizontal 173Escalabilidad
de microservicios 173Sincronización sobre Dinámica Asíncrona 175

Combinaciones de suscriptores de editor 176 Combinaciones de


instancias de suscriptor de editor 176 Procesamiento secuencial de
microservicios 179
Diseño de Microservicios de Procesamiento Secuencial
179Comprensión del Código 181Construir y ejecutar el
Procesamiento Secuencial de Microservicios 196Probar el
Procesamiento de Solicitudes Secuenciales 202Inspeccionar la
asignación de la partición de microservicios 207 Procesamiento
Paralelo de Microservicios 209

Diseño de Microservicios de Procesamiento Paralelo 210Paralelismo


y Seguridad de Hilos 211Entendiendo el Código 212Construyendo y
ejecutando el Microservicio Procesamiento Paralelo 214Probando el
Procesamiento Paralelo de Solicitudes 218Resumen 222

Capítulo 6: Microservicios orientados a mensajes de calidad de producción 223


Opciones de nivel de cable Inter-Microservicios 224
XML-RPC y SOAP 224REST y JSON-RPC 225RPC vs
Mensajería estilo 226RPC Métodos de Mensajería 226HTTP para
CRUD en Recursos 227

ix
Tabla de ConTenTs

Microservicios CRUD sobre Kafka en MongoDB 229


Diseñar CRUD sobre canal asíncrono en MongoDB 230Entender el
código fuente 231Construir y ejecutar el microservicio 240Probar los
microservicios 246CRUD de microservicios sobre Kafka en
PostgreSQL 248

Diseñar CRUD sobre canal asíncrono en PostgreSQL 249Entender el


código fuente 249Construir y ejecutar el microservicio 250Probar el
microservicio 255Agregar respuestas de múltiples microservicios 258

Patrón de integración del agregador 258Diseñar el Agregador de


Microservicios 260Entender el código fuente 261Construir y ejecutar
el microservicio 267Probar el microservicio 272Resumen 279

Capítulo 7: Presentando Docker 281


Diferentes tipos de virtualización 282
Despliegue tradicional 282Virtualización 283Contenedores
285Contenedores en Detalle 285

Historia de Contenedores 285Internos de contenedores


286Virtualización vs Contenedorización 287

x
Tabla de ConTenTs

Conceptos Docker 289


Sistemas de archivos en capas 289Imágenes Docker 289Imágenes
Docker vs Contenedores 293Registro Docker 297Hello World Tomcat
en Docker 299

Ejecuta Tomcat Container 299Build y ejecuta la aplicación Java sin


Java 307
Usando un contenedor Maven 308Creando un arquetipo Maven
308Construyendo y paquete usando Maven Container 311Deploy la
aplicación web usando Maven Container 314Build y ejecuta la
aplicación Java con Docker Compose 316

Usando Docker Compose 317Construye el primer microservicio Java


con Docker 320
Dockerización del microservicio usando Jib 320Entender el código
fuente: 321Compilar y enviar imágenes a Docker Hub 324Docker
Hub Registro y Repositorio 326Extraer imagen y ejecutar contenedor
328Construye un microservicio usando un archivo Docker 333

Dockerfiles 334Entendiendo el código fuente 334Construye y ejecuta


el microservicio usando un Dockerfile 336Resumen 343

xi
Tabla de ConTenTs

Capítulo 8: Contenedores de microservicio 345


Redes de contenedores 346
Enlaces 346Networks 347Container Logs 348

Registro de salida en consola 348 contenedores Microservice y


MongoDB usando enlaces 350
Diseño de la topología de contenedores 350Entendiendo el código
fuente 353Ejecutando contenedores usando Dockerfiles
353Probando los contenedores de microservicios 358 Contenedores
de microservicio y MongoDB usando una red 360

Diseño de la topología de contenedores 361Entendiendo el código


fuente361Ejecutar contenedores usando Dockerfiles 361Probando
los contenedores de microservicios 367Contenedor de microservicios
con PostgreSQL en el host 369

Diseño de la topología de contenedores 369Entendiendo el código


fuente 371Contenedor a PostgreSQL en configuración de host
371Ejecutar contenedores usando Dockerfiles 372Probar los
contenedores de microservicios 376Microservice y PostgreSQL en el
Contenedor 381

Diseño de la topología de contenedores 382Entendiendo el código


fuente383Ejecutando contenedores usando Dockerfiles
383Probando los contenedores de microservicio 388

xii
Tabla de ConTenTs

Almacenamiento de contenedores 393


Volúmenes 394 Contenedores de Microservicio y MongoDB usando
el montaje de archivo 394
Diseño de la topología de contenedores 395Entendiendo el código
fuente: 396Ejecuta contenedores usando Dockerfiles 397Prueba de
los contenedores de microservicios 401Resumen 404

Capítulo 9: Componiendo contenedores multiservicio 405


Presentamos Docker Compose 406
Docker Compose YAML 407Docker Compose Casos de Uso
408Componiendo Microservicios con Contenedores PostgreSQL 409

Componiendo la topología del contenedor 410Entendiendo el código


fuente 411Ejecutar contenedores usando Docker Componer
416Probar los contenedores de microservicios 421Componiendo
microservicios con contenedores de MongoDB 424

Componiendo la topología de contenedores 424Entendiendo el


código fuente 425Ejecutando contenedores usando Docker
Compone 427Probando los contenedores de microservicios
430Componiendo microservicios con PostgreSQL y Kafka 432

Componiendo la topología del contenedor 432Entendiendo el


código fuente 433Ejecutando contenedores usando Docker
Compone 439Probando los contenedores de microservicio 444

xiii
Tabla de ConTenTs

Componiendo microservicios con MongoDB y Kafka 447


Componiendo la topología del contenedor 447Entendiendo el código
fuente 448Ejecutando contenedores usando Docker Compose
449Probando los contenedores de microservicios 452Resumen 454

Capítulo 10: Microservicios con Kubernetes 455


El mundo de Kubernetes 456 Arquitectura Kubernetes 457

El Plano de Control 458El Nodo 459Kubernetes Despliegue 459

Contenedores 460Pods 460Réplicas Conjuntos 461Despliegue


461Acceso a los servicios Kubernetes 462

Acceso a despliegues de Kubernetes 462Servicio Kubernetes


463Enrutamiento de tráfico a Kubernetes 466

IP del clúster 466NodePuertos 467Balanceador de carga 469Ingress


470 Gestión del Estado 472

Escala vs Gestión Estatal 472StatefulSets 473

xiv
Tabla de ConTenTs

Reclamación de Volumen Persistente 475 Volumen Persistente 475


Clústeres de Kubernetes 476

Microservicios Minikube 476 y MongoDB en Kubernetes 476

Topología de despliegue de microservicios de diseño 477Entender el


código fuente 478Ejecutar microservicios en Kubernetes 489Probar
los Pods de Microservicios 499Acceder a Despliegues de Kubernetes
500Microservicios y PostgreSQL en Kubernetes 507

Topología de despliegue de microservicios 507Entender el código


fuente 508Ejecutar microservicios en Kubernetes 514Probar los Pods
de Microservicios 516Resiliencia de Kubernetes Cápsulas 519

Retención estatal 519Resumen 523

Capítulo 11: Microservicios orientados a mensajes en Kubernetes 525


Microservicios sobre Kafka con PostgreSQL en k8s 526
Diseñar la topología de orquestación de microservicios
526Entender el código fuente 527Ejecutar microservicios en
Kubernetes 534Probar los Pods de Microservicios 537Probar la
Carga de los Pods de Microservicio 541

xv
Tabla de ConTenTs

Microservicios sobre Kafka con MongoDB en k8s 544


Diseñar la topología de orquestación de microservicios 544Entender
el código fuente 545Ejecutar microservicios en Kubernetes
547Probar los Pods de Microservicios 549Probar la carga de los
Pods de Microservicios 549Conéctate con el Pod de MongoDB
usando kubectl 550Enrutamiento de entrada de microservicios 553

Topología de Enrutamiento de Entrada de Diseño


554Configuraciones del Entorno 554Comprensión del Código Fuente
556Ejecutar Entrada y Microservicios en Kubernetes 561Descripción
Ingress 563Probando los Microservice Pods 564Resumen 569

Capítulo 12: Automatización del despliegue de Kubernetes y Helm 571


Presentando un Microservicio Java Simple 572
Diseñando tus microservicios sencillos 572Organización del código
573Entendiendo el código fuente 574Construyendo y ejecutando el
microservicio 575Probando el microservicio 577Automatizando la
Construcción Docker 577

Entendiendo el código fuente 577Construye y ejecuta el


microservicio 579Prueba el microservicio 585

XVI
Tabla de ConTenTs

Automatización de Docker Push 586


Entendiendo el código fuente 586Construyendo y ejecutando el
microservicio 588Probando el Microservicio 591Automatizando el
despliegue de Kubernetes 591

Organización de código 591Construir y ejecutar el microservicio


593Probar el microservicio 594Helm 594

¿Qué es Helm? 595Nomenclatura de Helm 595Arquitectura de Helm


Cliente-Servidor 596Cómo funciona Helm Microservicio del Paquete
597Helm 599

Organización del Código 599Crear tu primer gráfico de Helm


600Confirmar la Precisión del Helm Chart 603Construir y ejecutar el
microservicio 605Probar el microservicio 608Helm Actualizaciones de
Lanzamiento 609Helm Rollback de Lanzamiento 612Helm-
Empaquetado Multi-Microservicios 614

Diseño de topología de despliegue basada en Helm


615Organización del código 615Entendiendo el código fuente
619Construyendo y ejecutando el microservicio 627Probando el
microservicio 629

XVII
Tabla de ConTenTs

Multi-Microservicios de Empaquetado Helmfile 631


Organización del Código 632Entendiendo el código fuente
634Construyendo y ejecutando el microservicio 637Probando el
microservicio 640Resumen 641

Capítulo 13: CI/CD para Contenedores de Microservicio 643


CI y CD 644
DevOps 644Integración Continua (CI) 645Entrega Continua (CD)
646Despliegue Continuo (CD) 646Google Skaffold 646

Ejemplo de flujo de trabajo Skaffold 647CI y CD para Microservicios


648
Organización de Código 648Entendiendo el código fuente
649Construyendo y ejecutando el microservicio 653Probando los
microservicios 655Resumen 659

Capítulo 14: Microservicios en AWS Elastic Compute Cloud 661


Computación en la Nube 662
Nubes Públicas 662Modelos de Despliegue de Nube 664
Computación Distribuida 665

XVIII
Tabla de ConTenTs

Amazon Web Services (AWS) 667


VPC 668Subnet 668Proxy Público Subred 669NAT Gateway 669EC2
670Tablas de Ruta 670Gateway de Internet 670Infraestructura como
Código (IaC) 671

Terraform 672Configuración de AWS EC2 usando Terraform 673

Diseña un mini centro de datos en la nube 673Código Organización


674Entendiendo el código fuente 675Construye y desmonta el
servidor EC2 en la nube 683Accediendo a tu EC2 en la nube de AWS
usando SSH 686Instalación de JRE en AWS EC2 687Despliegue de
microservicios en AWS EC2 688

Copia el ejecutable del microservicio a la nube 689Ejecuta el


microservicio 689Prueba el microservicio usando UI 691Resumen
692

Capítulo 15: Microservicios en el Servicio AWS Elastic Kubernetes 693


El servicio Amazon Elastic Kubernetes 694
Plano de control EKS 694EKS Nodos Trabajadores 694

xix
Tabla de ConTenTs

Configuración de AWS EKS usando Terraform 695


Diseñando una topología EKS en una AWS Cloud 695Código
697Entendiendo el código fuente 697Configuraciones necesarias
para operar un clúster EKS 708Construir e integrar tu clúster EKS
AWS 708Despliegando contenedores en AWS EKS 710

Probando el microservicio en EKS 713Resumen 715

Apéndice A: Usando cURL y Postman 717Apéndice B: Usando


MongoDB 727Apéndice C: Usando PostgreSQL 741Apéndice D:
Usando Kafka 777Apéndice E: Herramientas de contenedor
785Apéndice F: Nube Herramientas 813Índice 823

xx
Sobre el autor
Binildas A. Christudas es una arquitecta y
desarrolladora experimentada, especializada en la
integración de soluciones de software distribuido
para aerolíneas, hostelería y telecomunicaciones
desde la creación de Java. Actualmente dirige los
servicios tecnológicos como vicepresidente en IBS
Software, un líder en la aerolínea
Dominio del software de carga. Binildas está dedicada a la arquitectura de soluciones
de software altamente resilientes y altamente disponibles para algunas de las
mayores compañías de cruceros y aerolíneas del mundo. Se especializa en garantizar
la coherencia de datos entre sistemas distribuidos y descentralizados, abarcando
diversos escenarios como despliegues interregionales en grandes nubes públicas.
Binildas es ingeniero mecánico del College of Engineering de Trivandrum
(CET) con un título de posgrado en sistemas por el Institute of Management
Kerala (IMK). Con más de 25 años de experiencia en sistemas distribuidos,
actualmente dedica su enfoque a diseñar sistemas replicados, libres de
conflictos y que finalmente sean consistentes y que gestionen datos en
streaming y big data. Es autor de Practical Microservices Architectural
Patterns de Apress y Service Oriented Java Business Integration de Packt.
Binildas fue capitán del equipo de halterofilia de la Universidad de Kerala y
fue campeón nacional durante sus estudios. También ha recibido una patente
por "Un método y un sistema para facilitar la multitenencia de servicios" por
parte de la USPTO. Binil puede ser contactado a través de
[Link]/in/binildasca/.

xxi
Sobre el revisor técnico
Yogesh Sharma es un desarrollador de software
dinámico afincado en Pune, India, que
actualmente perfecciona sus habilidades en Nice
Actimize. Con un gran interés en el procesamiento
complejo de eventos (CEP), la programación low-
code/no-code (LCNC) y el desarrollo progresivo de
aplicaciones, Yogeshis siempre está dispuesto a
experimentar con tecnologías de vanguardia y
soluciones innovadoras. Fuera del trabajo, es un
padre entregado, pasando tiempo de calidad con
su hijo. Juntos, exploran los emocionantes mundos
del cohetería DIY y el patinaje, fomentando la
creatividad y el amor por el aprendizaje.

xxiii
Agradecimientos
Un gran agradecimiento a Apress Media por confiar en mí y darme la
oportunidad de escribir este libro. Nirmal Selvaraj, Dulcy Nirmala y
DivyaModi han sido de gran ayuda para que el proceso sea fluido.
El entorno de trabajo amigable con la tecnología en IBS Software ha sido una
gran ventaja para mí. Muchas gracias al Sr. V. K. Mathews, fundador y presidente
ejecutivo de IBSGroup, por proporcionarme una motivación constante a lo largo
de mi carrera. También quiero agradecer al Sr. Arun Hrishikesan, vicepresidente
senior de Innovation Ecosystem, IBS, por su motivación y apoyo constantes,
especialmente al ofrecer sus opiniones más amplias sobre las áreas tecnológicas,
que influyeron en gran medida en el contenido y estilo de este libro. Gracias
también a Christopher Branagan, CTO de IBS, por sus muchos años de mentoría.
También quiero agradecer a Arun Prasanth de IBS por hablar conmigo sobre
aspectos de este libro.
Gracias a mi esposa, Sowmya Hubert, y a mis hijas, Ann S. Biniland Ria S.
Binil, que sacrificaron tanto. Un enorme agradecimiento a mi padre, Christudas
Y., y a mi madre, Azhakamma J., por su apoyo desinteresado, que me ayudó a
llegar hasta donde estoy hoy. También, una nota de agradecimiento a mis
suegros, Hubert Daniel y Pamala Percis. Por último, gracias a mi hermana, la
Dra. Binitha, a su marido, el Dr. Segin Chandran, y a su hija, Aardra B. S.

xxv
Introducción
Los microservicios prometen el santo grial: liberaciones simultáneas y
escalabilidad selectiva. ¿Cómo puedes hacerlo de forma nativa en la nube?
¿Pueden los microservicios eliminar el RPC síncrono y adoptar interacciones
asíncronas basadas en mensajes? Cuando haces eso, ¿cómo garantizas la
experiencia del usuario con el mismo modo síncrono de interacción? En este
libro, aprenderás sobre estos patrones y prácticas no triviales, todos con
código de ejemplo de calidad de producción que puedes usar como plantillas
para empezar tu propio trabajo.
Con 25 años de experiencia, te enseño las arquitecturas hexagonal y cebolla, que
de otro modo son difíciles de entender, y las demuestro con muestras concretas
en Spring Boot. Si sabes lo suficiente de Java y Spring, puedes aprender
conceptos básicos a avanzados, incluyendo replicar instancias del mismo
microservicio y correlacionar solicitudes y respuestas de usuarios concurrentes a
la misma instancia, tanto en RPC como en estilos de mensajería. Aprenderás a
hacer esto en procesos Java independientes, en contenedores Docker, en
Kubernetes y en AWS Cloud usando el Elastic Kubernetes Service (EKS).
Lo que hay dentro:

• Crea un microservicio sencillo en Spring Boot


• Aprende sobre HATEOAS, hexagonales y
onionarchitectures, con ejemplo de código

• Construir múltiples microservicios interactuando a través


de RPC y mensajería

• Utiliza patrones asíncronos en cada nivel, pero con la


frecuencia de las solicitudes de usuario a la misma
instancia o a instancias diferentes

xxvii
InTroduCTIon

• Aprende sobre CI y CD y empaquetado de Helm, con


ejemplos de código

• Compilar paquetes Docker y desplegarlos en Kubernetes

• Desplegar microservicios en AWS EC2 y EKSSpring Boot ayuda a los


desarrolladores a crear aplicaciones que simplemente se ejecutan. Cuando se
requiere una configuración mínima para crear una aplicación, incluso
desarrolladores novatos en Java pueden hacerlo. No hay razón para que esta
simplicidad limite a los desarrolladores a la hora de abordar requisitos
empresariales complejos, y ahí es donde la arquitectura de microservicios con
Spring Boot ayuda. Además de desplegar, parchear o escalar aplicaciones
rápidamente, los contenedores ofrecen soluciones que también pueden apoyar
esfuerzos ágiles y DevOps para acelerar los ciclos de desarrollo, pruebas y
producción. La nube ayuda a las empresas a escalar y adaptarse rápidamente,
acelerar la innovación y fomentar la agilidad empresarial, sin una gran
inversión inicial en TI. ¿Y si pudieras equipar incluso a un desarrollador
novato con todo lo necesario para ayudar a las empresas a hacer todo esto?
Este libro simplemente hace eso, y más.

xxviii
CAPÍTULO 1

Microservicios
para la Empresa
Ha pasado más de una década desde que se discutieron y consideraron las
ideas originales y variantes de microservicios. Hoy en día, este estilo
arquitectónico es la norma, no la excepción. Sus herramientas y frameworks
han madurado lo suficiente y los principios de arquitectura han sido probados
y probados, tanto en las instalaciones como en la nube. Hay suficiente claridad
sobre cómo esta arquitectura de software se diferencia de sus predecesoras,
por lo que este capítulo solo trata algunos puntos clave que no se han tratado
en otro lugar.
Este capítulo comienza analizando una visión general del paradigma informático y
explicando dónde encajan las tendencias actuales de los microservicios. Aprenderás
que los microservicios son otra forma de computación distribuida, pero los verdaderos
beneficios de los microservicios se cosechan cuando se proporciona una capacidad
descentralizada en el procesamiento de transacciones empresariales para los
componentes de microservicios. La descentralización aporta autonomía a los
microservicios de supermercado, lo que aporta una característica distintiva a las
transacciones empresariales, llamada consistencia eventual. Con el tiempo, los
sistemas consistentes son más tolerantes a fallos y proporcionan fiabilidad para
transacciones empresariales de extremo a extremo, que ocurren a través del protocolo
de transporte basado en HTTP, que por lo demás es relativamente menos estable. El
capítulo examina a continuación los límites entre microservicios y servicios "no tan
micro", cubiertos en el servicio

© Binildas A. Christudas 2024B. A. Christudas, Microservicios 1


Java y contenedores en la nube,[Link]
0555-4_1
Capítulo 1 MiCroservices para la empresa

Discusión sobre la granularidad. Antes de cerrar este capítulo, también


presento la noción de la arquitectura hexagonal con un ejemplo. También
hay más ejemplos de la arquitectura hexagonal en el capítulo 2.
Este capítulo cubre los siguientes temas:
• Diferentes paradigmas de arquitectura informática

• Sistemas de software coherentes eventualmente

• Granularidad del servicio


• La metáfora de la arquitectura hexagonal

• Tu primer microservicio Java en código

Paradigmas de Arquitectura Informática


Es importante entender la naturaleza distribuida de los servicios en el
estilo de arquitectura de microservicios, por lo que esta sección explica
qué es esta arquitectura y cómo se diferencia de otras contrapartes más
familiares.

Computación Centralizada
En comparación con los miniordenadores o ordenadores personales, que hoy en día
son comunes y son una mercancía, los mainframes tienen más potencia de
procesamiento. Las primeras versiones de los ordenadores mainframe tenían un
gran armario, llamado mainframe, que alojaba la unidad central de procesamiento y
la memoria principal. Los mainframes se caracterizan por terminales de usuario
interactivos que operan como ordenadores de tiempo compartido, soportando a
cientos de usuarios simultáneamente junto con el procesamiento por lotes. Los
mainframes se utilizan para el procesamiento de transacciones comerciales, como
reservas de aerolíneas, banca, etc. Una transacción abarca un conjunto de
operaciones que incluyen E/S de disco, llamadas al sistema operativo y otras formas
de transferencia de datos de un subsistema a otro, como se muestra en la Figura 1-1.

2
Capítulo 1 MiCroservices para la empresa

Figura 1-1. Computación centralizada

Como se muestra, los mainframes son ordenadores centralizados que operan


en modo de tiempo compartido, soportando a cientos de usuarios
simultáneamente junto con el procesamiento por lotes. Los usuarios acceden a
mainframes a través de terminales de teclado/máquina de escribir y pantallas
CRT especializadas con teclados integrados. Pantalla verde es el nombre
común para esos monitores monocromáticos usados para el acceso del usuario,
ya que tradicionalmente usaban una pantalla verde de fósforo "P1".

1 Los monitores monocromos suelen estar disponibles en tres colores: si se usa el


P1phosphor, la pantalla es verde monocroma. Si se usa el fósforo P3, la pantalla es
monocromo ámbar. Si se utiliza el fósforo P4, la pantalla es blanca y monocroma
(conocida como "blanco de página").

3
Capítulo 1 MiCroservices para la empresa

El procesamiento de transacciones o procesamiento por lotes se ofrecía


como un servicio por el sistema central de mainframe, por lo que esta
arquitectura se clasifica mejor bajo el paradigma de computación
centralizada, donde un ordenador central toma todas las decisiones sobre la
finalización exitosa de la transacción comercial, de extremo a extremo.

Computación distribuida
A continuación llegó el paradigma de computación distribuida, donde los
diferentes componentes del sistema de cómputo estaban ubicados en
distintos ordenadores en red, y se comunicaban y coordinaban sus acciones
evitando mensajes entre sí. Mientras lo hacía, típicamente, uno de los
thenodes o ordenadores actuaba como coordinador de la transacción
comercial: coordinaba (o orquestaba) componentes computacionales
elementales de la transacción empresarial global en diferentes ordenadores
en red y decidía el éxito o fracaso de la transacción.
La computación distribuida se presenta en diferentes variantes. Los
principales se enumeran aquí:

• Cliente-servidor: En una arquitectura cliente-servidor,


los clientes solicitan y reciben datos de los servidores y
los muestran a los usuarios. La máquina cliente aloja la
mayoría de las reglas y validaciones necesarias para que
la lógica de negocio se complete. Los clientes gruesos
son característicos de esta arquitectura, y la distribución
cliente-binaria es complicada aquí

• Tres niveles: Una arquitectura de tres niveles traslada la


inteligencia del cliente a un nivel intermedio para que se
puedan usar clientes sin estado y delgados. Esto simplifica
el despliegue de aplicaciones a un solo servidor middleware,
y la distribución clientebinaria es nula o mínima. La
mayoría de las aplicaciones web son de tres niveles.

4
Capítulo 1 MiCroservices para la empresa

• N-nivel: Una arquitectura N-tier, también conocida como


arquitectura multi-nivel, es un patrón de diseño de
ingeniería de software que separa una aplicación en capas
lógicas y capas físicas. Cada capa tiene una
responsabilidad y funcionalidad específicas, y los niveles
suelen estar separados por límites físicos o lógicos, como
diferentes servidores, procesos o redes.

• Peer-to-peer: En esta arquitectura, no existen máquinas


concretas que proporcionen un servicio o gestionen los
recursos de red. En cambio, todas las responsabilidades se
reparten uniformemente entre todas las máquinas,
conocidas como pares. Cada peer puede servir tanto como
cliente como servidor. Ejemplos de esta arquitectura
incluyen BitTorrent. La bitcoinnetwork también es una
especie de peer to peer, pero bitcoinnetwork encaja más en
otro paradigma informático llamado arquitectura
descentralizada, que se explica en breve.

• Microservicios: Los microservicios son un tipo de arquitectura


distribuida donde se identifican las unidades funcionales como base
para la distribución. Por ello, en muchos casos se necesita más de un
microservicio para completar una única transacción comercial. Los
microservicios con capacidades de diseño adicionales pueden
clasificarse en otra clase de paradigma informático, llamado
descentralizado, que se discute más adelante en este capítulo. La figura
1-2 representa una arquitectura distribuida. Aquí, los procesos cliente,
negocio y base de datos están separados por la red.

5
Capítulo 1 MiCroservices para la empresa

Figuras 1-2. Computación distribuida

6
Capítulo 1 MiCroservices para la empresa

En la Figura 1-2, se muestra un único servidor de nivel intermedio.


Este servidor está compuesto por un conjunto de módulos de negocio:

• Disponibilidad: Un módulo que ayuda a planificar un


vuelo, durante el cual un viajero puede introducir las
fechas y destinos de viaje y obtener una lista de todos los
vuelos disponibles de diferentes aerolíneas, a través de lo
que se llama un Motor de Reservas por Internet (IBE). El
viajero puede revisar esta lista, comparar los precios y
luego decidir cuál reservar.

• Reserva: El módulo de reserva ayuda al viajero a


reservar un vuelo y crear un Registro de Nombre del
Pasajero (PNR) para el viaje en el vuelo preseleccionado.

•Inventario: Cuando se completa una reserva de asientos en un vuelo, el


inventario de asientos debe reducirse en el módulo Inventario. En algunos
casos, el servidor de nivel medio también se conecta a otros sistemas de
terceros como un Sistema de Distribución Global (GDS) como Amadeusor
Sabre, mostrando así el paradigma de computación distribuida en el sentido
más estricto. Esto se muestra en la notación de malla distribuida en las
Figuras 1-2.

Computación descentralizada
En la computación descentralizada, los servicios de aplicación se realizan
mediante dispositivos informáticos individuales o nodos en una red distribuida,
sin ubicación central. Este enfoque para el desarrollo (y distribución) de
software ofrece a los desarrolladores gran flexibilidad y ahorros, ya que no
tienen que crear un punto de control central. Bitcoin, Ethereum y Uniswap son
algunos de los protocolos que utilizan computación descentralizada.

7
Capítulo 1 MiCroservices para la empresa

Las figuras 1-3 muestran una arquitectura de microservicios, que está


obviamente distribuida. Diferentes componentes de las transacciones
comerciales de extremo a extremo también podrían estar repartidos entre
distintos componentes, así que, de alguna manera, esto es descentralizado.

Figuras 1-3. Computación descentralizada

8
Capítulo 1 MiCroservices para la empresa

No hablo de las complejidades de por qué las Figuras 1-3 muestran la arquitectura
de microservicios, ya que supongo que los lectores están familiarizados con esos
conceptos básicos. Aquí tienes algunas de las características de esta arquitectura:

• Distribuida: La aplicación empresarial se divide y


distribuye según la funcionalidad (las opciones de
compra en aerolíneas, la gestión de reservas y el
inventario son las funcionalidades).

• Independiente: Cada uno de los microservicios puede


desarrollarse y desplegarse de forma independiente de
los demás (siempre que mantengas compatibilidad
API para la comunicación entre microservicios).

•Disponibilidad: Si uno de los microservicios no está en funcionamiento,


los usuarios pueden seguir obteniendo funcionalidad de la aplicación a
través de otros microservicios que están en ejecución (si Booking está
caído, el usuario aún puede hacer algunas compras). Así, en cierto modo,
una arquitectura de microservicios con las primitivas de diseño
adecuadas también puede funcionar como una aplicación descentralizada
(aunque la nomenclatura de descentralizado es más aplicable a
aplicaciones que involucran blockchains).

Sistemas de Software Consistentes Eventualmente


Es importante entender la naturaleza distribuida de los servicios en el estilo
arquitectónico de microservicios. Esta sección explica qué es esto y en qué
se diferencia de otras arquitecturas equivalentes más conocidas.

Consistencia atómica
La Figura 1-4 es la arquitectura distribuida mostrada en la Figura 1-2, pero
aquí un usuario está reservando un vuelo.

9
Capítulo 1 MiCroservices para la empresa

Figuras 1-4. Transacciones ACID

Consultando la Figura 1-4, una transacción típica de reserva de vuelos se


realiza así:

1. El navegador envía la transacción del usuario al


servidor de nivel empresarial.

2. Dado que la transacción es una reserva de vuelo, es


interceptada por el módulo de Reserva. Antes de realizar
la reserva, el módulo de reserva envía una solicitud de
inventario de actualización al módulo de Inventario para
reducir el inventario de asientos, tras iniciar una
transacción ACID2.

2 ACID significa Atomicidad, Consistencia, Aislamiento y Durabilidad. Si una operación de


base de datos tiene estas propiedades ACID, puede llamarse transacción ACID, y los sistemas de
almacenamiento de datos que aplican estas operaciones se denominan sistemas transaccionales.

10
Capítulo 1 MiCroservices para la empresa

3. Dentro de la transacción ACID iniciada


previamente, el módulo de inventario actualiza la
tabla inventorydatabase.

4. Si la actualización del inventario tiene éxito, el módulo de reservas creará


una reserva en su tabla de base de datos, dentro del mismo contexto de
transacción. Si las tablas de reserva e inventario están en la misma base de
datos, y si los componentes de reserva e inventario son dos módulos en el
mismo servidor intermedio, la transacción es local. Eso significa que las dos
actualizaciones de tabla serán exitosas o se revertirán de forma atómica
(ACID).

Consistencia eventual
Esta sección considera el mismo escenario de reserva de vuelos en una arquitectura
de microservicios, donde el procesamiento se distribuye. Ver Figura 1-5.

Figuras 1-5. Transacciones entre microservicios

11
Capítulo 1 MiCroservices para la empresa

El mismo escenario de transacción comercial de reserva de vuelos ocurre


ahora así:

1. La app de Reserva enviará la transacción del usuario


al servidor de nivel empresarial.

2. Dado que la transacción es la reserva de un vuelo, es


interceptada por el microservicio de reserva. Antes de
realizar la reserva, el microservicio de reserva envía una
solicitud de actualización de inventario al microservicio de
inventario para reducir el inventario de asientos. Sin
embargo, no puedes iniciar una transacción global y enviar
la solicitud de actualización de inventario en la misma
transacción global. Esto se debe a que la solicitud de
inventario de actualización suele ser una invocación REST
síncrona, y no se fomentan las transacciones distribuidas
entre microservicios. Sin un contexto de transacción
distribuida, el servicio de reservas recibe un éxito o un
fallo para la solicitud de inventario de actualización.

3. El módulo de inventario actualiza la tabla de


inventariodatabase y envía un éxito o un fracaso.

4. Si la actualización de inventario tiene éxito, los microservicios de reserva


crearán una reserva en su tabla de base de datos y enviarán un mensaje de
éxito al usuario final. Aquí hay un truco. Si por casualidad el intento de
actualizar la tabla inventorydatabase tiene éxito, pero los microservicios de
reservas no logran crear una reserva en la tabla de la base de datos de
reservas, hay un problema en los datos de consistencia entre estas dos tablas.
Necesitas intervención manual para corregir esto y que estos dos
microservicios vuelvan a ser finalmente consistentes.

12
Capítulo 1 MiCroservices para la empresa

Sistemas finalmente consistentes y descentralizados


He iniciado una discusión sobre cómo hacer que los microservicios sean
eventualmente consistentes. También he hablado sobre cómo manejar el escenario
en el que la tabla de actualización de la base de datos de inventario tiene éxito, pero
los servicios de microservicios de reservas no logran crear una reserva en la tabla
de la base de datos de reservas. Ahora consideremos el escenario contrario: ¿qué
pasa si el microservicio de inventario no está funcionando y los microservicios de
reserva no pueden completar la reserva? Este escenario ocurre cuando la invocación
REST de estilo síncrono desde los microservicios de reserva al microservicio de
inventario no puede completarse, por lo que la creación de reservas también fallará.
Las figuras 1-6 muestran una improvisación sobre la arquitectura
mostrada en la Figura 1-5, conectando un canal basado en eventos.

Figuras 1-6. Microservicios descentralizados

13
Capítulo 1 MiCroservices para la empresa

Aquí, los microservicios no están estrechamente acoplados. En su lugar, puedes


usar un protocolo de mensajería tipo JMS o AMQP ligeramente acoplado. La
secuencia de la transacción de negocio de reserva de vuelos podría ser la siguiente:

1. El navegador envía la transacción del usuario al


servidor de nivel empresarial.

2. Dado que la transacción es una reserva de vuelo, es


interceptada por el microservicio de reserva. Antes de
realizar la reserva, el módulo de Reserva envía un mensaje
de "vuelo reservado" al canal de mensajería.

3. El microservicio de reservas creará una reserva en su


tabla de base de datos y proporcionará la respuesta al
usuario final.

4. El mensaje de "vuelo reservado" será recogido por


cualquier otro microservicio interesado—en este caso, el
microservicio de inventario.

5. Los microservicios de inventario actualizan la tabla inventorydatabase y,


opcionalmente, envían un mensaje de éxito o fracaso al canal de mensajería.
Es posible mejorar la fiabilidad de esta transacción comercial manteniendo
los Pasos 2 y 3 en el ámbito de la transacción. Independientemente de eso, un
cambio notable en el diseño es que la transacción comercial se extiende a
través de múltiples microservicios, y la finalización exitosa de la transacción
está determinada por la finalización global de las transacciones por estos
diferentes microservicios, finalmente. Ningún microservicio es el único
responsable de controlar el flujo completo de extremo a extremo. En cambio,
cada microservicio cumple su parte, haciendo que la arquitectura sea
realmente descentralizada. Cabe señalar que esta discusión asumía que existía
suficiente inventario. Puede haber escenarios más complejos en los que el
inventario es limitado, pero esto va más allá del alcance aquí.

14
Capítulo 1 MiCroservices para la empresa

Granularidad del servicio


Una apreciación adecuada de los diferentes niveles de granularidad de una
arquitectura de servicios te ayudará a comprender sus posibilidades y
limitaciones, por lo que esta sección analiza estas granularidades de servicios.

Monolito
Las figuras 1-7 ilustran una arquitectura monolítica típica. En esta arquitectura,
los módulos funcionales solo están separados lógicamente, pero todos están
empaquetados físicamente en un único archivo .ear (archivo empresarial).

Figuras 1-7. Una arquitectura monolítica

Muchas veces, una arquitectura monolítica se comunica con una base de datos
en un nodo diferente, y todos los módulos funcionales están acoplados
estrechamente a esta única base de datos.

15
Capítulo 1 MiCroservices para la empresa

Macroservicio
La arquitectura de macroservicios mostrada en las Figuras 1-8 es una
mejora de empaquetado respecto a la arquitectura monolítica.

Figuras 1-8. Una arquitectura de macroservicios

En la arquitectura de macroservicios, diferentes módulos funcionales se


empaquetan por separado, en .jars separados (archivos Java). El esquema de
despliegue de una arquitectura de macroservicios es similar al de un
monolito. Todos los archivos Java se colocan en un único .ear o .war (archivo
web) y luego se despliegan en un solo nodo.

Mini Servicio
Una arquitectura de mini servicio es un intento genuino de improvisar sobre un
monolito o macroservicio. Las figuras 1-9 muestran una arquitectura de mini servicios.

16
Capítulo 1 MiCroservices para la empresa

Figuras 1-9. Una arquitectura de mini servicio

Como se muestra en las Figuras 1-9, una arquitectura de mini servicio también
empaquetará módulos en archivos separados, similar a una arquitectura de
macroservicios. Además, algunos de estos archivos también pueden empaquetarse
en archivos desplegables separados. Sin embargo, en muchos casos, estos
archivos de despliegue se despliegan en el mismo nodo debido a limitaciones
arquitectónicas como bibliotecas dependientes, modos de comunicación, etc.

Microservicios
La arquitectura de microservicios intenta proporcionar flexibilidad total en cuanto
al desarrollo, despliegue y lanzamiento, como se muestra en la Figura 1-10.

17
Capítulo 1 MiCroservices para la empresa

Figura 1-10. Una arquitectura de microservicios

Una ventaja notable de la arquitectura de microservicios es que promueve


tecnologías poliglotas. Esto da a cada microservicio la flexibilidad para
adoptar su propia tecnología y arquitectura de implementación, pero aún
exponiendo e interactuando con microservicios entre pares usando
protocolos estándar.

La metáfora de la arquitectura hexagonal


Cuando se aprende sobre sistemas débilmente acoplados, especialmente en el
contexto de microservicios, es útil hablar sobre la arquitectura hexagonal. Yo
hago eso en esta sección.
Para entender esta metáfora, comienzo la discusión con la arquitectura
típica en capas.

18
Capítulo 1 MiCroservices para la empresa

Arquitectura en capas
Una arquitectura en capas se refiere a la organización típica de
arquitectura de software que se sigue a preocupaciones separadas,
principalmente las de comunicación, como se muestra en la Figura 1-11.

Figuras 1-11. Arquitectura en capas

En la arquitectura en capas de la Figura 1-11, las capas superior e inferior


son simplemente puntos de entrada/salida hacia y desde la aplicación.

La arquitectura de puertos y adaptadores


La arquitectura de los puertos y adaptadores fue mencionada por Alistair
Cockburn en su blog en 2005. Dice lo siguiente:

"permitir que una aplicación sea impulsada por igual por


usuarios, programas, scripts de prueba o lotes automatizados, y
ser desarrollada y probada aislada de sus dispositivos y bases
de datos de ejecución eventuales."

19
Capítulo 1 MiCroservices para la empresa

Para explicar mejor, piensa en una aplicación como el artefacto central de un


sistema, donde toda la entrada llega y toda la salida sale de la aplicación a
través de un puerto o puertos que aísla la aplicación de todo tipo de
herramientas, tecnologías y mecanismos de entrega externos. La aplicación no
debe tener conocimiento de quién o qué envía la entrada o recibe la salida.
Esto pretende proteger las aplicaciones frente a la evolución de la tecnología y
los requisitos empresariales, ya que tal evolución puede hacer que las
aplicaciones queden obsoletas poco después de desarrollarse.
Para entender la arquitectura de puertos y adaptadores, primero se convierte
la arquitectura en capas de la orientación típica norte-sur a una orientación
este-oeste, como se muestra en la Figura 1-12.

Figura 1-12. La arquitectura en capas, la orientación cambió

La figura 1-12 muestra el flujo típico de la aplicación, que comienza


desde el código en la interfaz de usuario, pasando por el núcleo de la
aplicación hasta el código de infraestructura, volviendo al núcleo de la
aplicación, entregando finalmente una respuesta a la interfaz de usuario.

20
Capítulo 1 MiCroservices para la empresa

La arquitectura de puertos y adaptadores resuelve el problema de


proteger y reutilizar las capas internas (capa de negocio) utilizando una
capa de abstracción, implementada como puerto y adaptador.

• Puertos: Un puerto es un punto de entrada y salida


independiente del consumidor hacia/desde la
aplicación. En Java, es una interfaz Java. O, en
términos más abstractos, podría ser una interfaz HTTP
REST o una interfaz de mensajería JMS o AMQP.

•Adaptador: Una clase adaptadora implementa una interfaz conocida


por sus clientes y proporciona acceso a una instancia de una clase
que no conocen sus clientes. Un objeto adaptador proporciona la
funcionalidad prometida por una interfaz sin tener que asumir qué
clase se usa para implementar esa interfaz. La arquitectura de
puertos y adaptadores identifica explícitamente tres bloques
fundamentales de código en un sistema:

1. Interfaz: Código que permite ejecutar una interfaz de


usuario, independientemente del tipo de interfaz que
pueda ser.

2. Negocio: El código de lógica de negocio, o


application core, que utiliza la interfaz de usuario para
hacer que las cosas sucedan.

3. Infraestructura: El código de infraestructura que conecta el núcleo de la


aplicación con herramientas como una base de datos, una cola de mensajes o
un tercero [Link] la orientación actual en la Figura 1-12, los adaptadores del
lado izquierdo, que representan la interfaz, se llaman adaptadores primarios
o de conducción porque inician una acción sobre la aplicación. Los
adaptadores del lado derecho,

21
Capítulo 1 MiCroservices para la empresa

Representando las conexiones a los recursos del backend, se llaman


adaptadores secundarios o adaptadores conducidos porque siempre
reaccionan a una acción de un adaptador primario.
Los adaptadores primarios o de conducción proporcionan servicios (a la
interfaz de usuario), mientras que los adaptadores secundarios o de
conducción consumen servicios (de la infraestructura). Por tanto, en el lado
izquierdo, tanto el puerto como su implementación concreta (el caso de uso)
pertenecen dentro de la aplicación. En el lado derecho, el puerto pertenece
dentro de la aplicación, pero su implementación concreta pertenece al
exterior. Envuelve parte de cierta infraestructura externa de algún proveedor.

Arquitectura hexagonal
La figura 1-12 muestra dos caras: una entrada a la aplicación usando la
interfaz de usuario y la otra una salida de la aplicación hacia una
infraestructura. Así, aunque hay dos lados simétricos (izquierdo y derecho) de
la aplicación, cada lado puede tener varios puntos de entrada/salida. Por
ejemplo, una API (por ejemplo, REST API) y una Interfaz Gráfica de Usuario
(GUI) pueden ser dos puntos de entrada/salida diferentes en el lado izquierdo
de la aplicación, mientras que una base de datos y una cola de mensajes
pueden ser dos puntos distintos de entrada/salida en el lado derecho de la
aplicación. Para representar que esta aplicación puede tener múltiples puntos
de entrada/salida, se dibuja el diagrama de la aplicación con varios lados. El
diagrama podría haber sido cualquier polígono con varios lados, pero la
elección resultó ser un hexágono, de ahí el nombre de arquitectura hexagonal.

Metamodelo de microservicios
Ahora puedo ampliar la noción de arquitectura hexagonal a un
microservicio, ya que muchos de los aspectos tratados en la sección de
puertos y adaptadores tienen sentido en el contexto de un
microservicio. Esto se muestra en la Figura 1-13.

22
Capítulo 1 MiCroservices para la empresa

Figuras 1-13. El metamodelo de microservicios

Ahora puedes comparar el metamodelo de microservicios mostrado en la


Figura 1-13 con el de un microservicio basado en Java Spring con los
siguientes componentes:

• Controlador REST: Una clase de controlador basada en


REST basada en HTTP, anotada con @RestController.

23
Capítulo 1 MiCroservices para la empresa

• Servicio POJO: La lógica central del negocio. Esta


clase debe estar protegida de cualquier cambio de
entrada o salida para facilitar la reutilización.

• Repositorio ORM: Una clase de repositorio ORM que


maneja lógica de persistencia a una base de datos.

• Entidad agregada: Entidad de dominio basada en el


modelo de dominio, que es reutilizable.

• Almacenamiento de datos: El almacenamiento persistente de la infraestructura.


• Escuchador de mensajes: una clase JMS o
una clase controladora basada en AMQP.

• Programa cliente: Programa que usará puertos para


salir a otros tipos de infraestructura.

• Proceso: Un modelado de negocio complejo requeriría un


modelado de procesos, que es opcional. Si se trata de un
modelado de procesos, la relación abstracta de
metamodelo entre un proceso y un servicio es la que se
muestra en la Figura 1-14.

24
Capítulo 1 MiCroservices para la empresa

Figuras 1-14. Relación de proceso vs. de servicio

• Un servicio expuesto a la interfaz de servicio.


• Un servicio puede ser un conjunto de otros servicios.

• Un proceso agrega y orquesta muchos servicios, o


incluso otros procesos.

•Un proceso también expone una interfaz de servicio. Las discusiones


posteriores siguen el metamodelo de microservicios mostrado en la Figura 1-
13 para representar muchos de los escenarios futuros.

Tu primer microservicio Java


Estoy seguro de que ya has tenido suficiente teoría, así que es hora de
crear tu primer microservicio en Java.
Este ejemplo utiliza Spring Boot para construir los microservicios Java. La base
de código del proyecto puede importarse a cualquiera de tus IDE favoritos, pero
también podrían construirse y ejecutarse sin un IDE y con la ayuda de comandos

25
Capítulo 1 MiCroservices para la empresa

en un terminal de Windows o Mac. Los capítulos posteriores utilizan un


enfoque similar, ya que la discusión sobre qué IDE usar y cómo emplear un
IDE específico está fuera del alcance de este libro. Supongo que ya conoces
esos pasos o puedes consultar un libro introductorio de Java o JEE.

Bota de muelle
Spring Boot utiliza una visión opinativa de la plataforma Spring y de muchas
bibliotecas Java de terceros, de modo que es sencillo crear aplicaciones
independientes, de calidad de producción, basadas en Spring que puedes
"simplemente ejecutar". Spring Boot sigue muchas convenciones y patrones de
uso seguidos por los desarrolladores, que han estado aprovechando al usar Spring
y otras librerías de terceros. Por lo tanto, la mayoría de las aplicaciones Spring
Boot necesitan una configuración de muelle muy pequeña. De nuevo, la intención
no es cubrir detalles de Spring Bootin; Eso está fuera del alcance de este capítulo.
Los lectores que ya estén familiarizados con Java o Spring no deberían tener
problema en empezar visitando la página principal de Spring Boot.

Diseña tu primer microservicio hexagonal


Esta sección comienza con una versión recortada de la vista hexagonal de
microservicios mostrada en la Figura 1-13. Lo mismo se muestra en la Figura 1-15.

26
Capítulo 1 MiCroservices para la empresa

Figura 1-15. Microservicio web de producto

Consideremos las Figuras 1-15 usando el lenguaje de puertos y adaptadores.


Se utiliza un puerto AnHTTP, que no es más que una especificación de cómo el
navegador del usuario puede usar el núcleo de la aplicación. Este puerto
(interfaz) pertenece dentro de la lógica de negocio como controlador REST. La
entidad Producto cumple con el núcleo de aplicación. Véase la Figura 1-16.

27
Capítulo 1 MiCroservices para la empresa

Figura 1-16. Entidades centrales de microservicios web de producto

En la Figura 1-15, he eliminado intencionadamente los componentes de servicio y el


proceso de la Figura 1-13 para hacer que la primera muestra sea bastante sencilla. A
continuación, usarás un adaptador de base de datos para conectarte a una base de datos
en memoria. De nuevo, para simplificar el primer ejemplo, no he diseñado un
adaptador. En su lugar, utilicé una dependencia directa a una clase de base de datos en
memoria. En el siguiente capítulo, verás cómo usar un adaptador de la manera correcta.
ProductRestController es el adaptador principal o controlador que envuelve un
puerto HTTP. Lo usas para decirle al núcleo de la aplicación qué hacer.
Traduce todo lo que viene del mecanismo de entrega (en este caso una
petición de navegador) a una llamada de método en el núcleo de la aplicación.

Organización del código


El código fuente de este libro está disponible en GitHub a través de la página
de producto del libro, ubicada en [Link]/9798868805547. El código
de la muestra está organizado como se muestra en la Lista 1-1, dentro de la
carpeta ch01\ch01-01. Esto sigue la estructura estándar de Maven, por lo que
[Link] está en la raíz del directorio.

28
Capítulo 1 MiCroservices para la empresa

Listado 1-1. Organización del código fuente de Spring Boot

├── 02-ProductWeb│├── [Link]│├── [Link]│├──


[Link]│├── [Link]│├── [Link]│└── src│└── Main│├──
Java││└── com││└─ Acme││└─ ecom││└── Producto│││├
Producto││├ ── [Link]││├──
[Link]││├── Mando││├──
[Link]│││└─ [Link]││├──
DB││└── [Link]││└─ Modelo││├── [Link]││└──
[Link]│└── Recursos│├──
Aplicació[Link]│├── [Link]│└──
Static│├── CSS││├── [Link]││└── [Link]

29
Capítulo 1 MiCroservices para la empresa

│├── JS││├── [Link]││├── Mando│││└──


product_controller.js││└── Servicio││└──
product_service.js│└─ [Link]├──
[Link]├── [Link]├── [Link]├──
[Link]└── [Link]

La carpeta ch01\ch01-01\02-ProductWeb\src\main\java contiene el código


fuente del microservicio. La carpeta ch01-01\02-ProductWeb\src\main\resources
contiene las configuraciones del microservicio así como el código fuente de la
aplicación web, que ayudará a los usuarios finales a interactuar con el
microservicio mediante una interfaz de navegador. La carpeta superior también
contiene scripts que te ayudarán a construir y ejecutar el microservicio.

Entendiendo el Código
Mantengo la entidad de dominio muy simple para este primer ejemplo. La entidad
es un producto típico que puede listarse en un sitio de comercio electrónico. Varios
productos entran en una categoría de producto, así que en el sitio primero puedes
mostrar las categorías de productos y los usuarios pueden explorar o navegar por las
categorías de productos para ver todos los productos disponibles en la categoría
seleccionada. Veamos primero estas entidades, como se muestra en los Listados 1-2.

30
Capítulo 1 MiCroservices para la empresa

Listado 1-2. Modelo de dominio de categorías de producto/producto


(ch01\ch01-01\02-
ProductWeb\src\main\java\com\acme\ecom\product\model\[Link])

clase pública Product {

@Idprivate Producto de
cadena; nombre privado
String; código de cadena
privado;; título privado de
String; privado Doble
precio;}clase pública
ProductCategory {

@Idprivate ID de cadena;
nombre privado de cadena;
título privado de String;
descripción privada de la
cadena; String privado
imgUrl;}

Estas entidades son sencillas, por lo que no se explican más. A


continuación, consideremos el puerto HTTP compatible con REST,
usando un SpringRestController, como se muestra en los Listados 1-3.

31
Capítulo 1 MiCroservices para la empresa

Listados 1-3. Puerto HTTP basado en REST para getAllProducts (ch01\ch01-01\02-


ProductWeb\src\main\java\com\acme\ecom\product\controller\ProductRestControll
[Link])

@RestControllerpublic class
ProductRestController{

@Autowiredprivate InMemoryDB
inMemoryDB;@RequestMapping(value =
"/productsweb",
método = [Link],produces =
{MediaType.APPLICATION_JSON_VALUE})Public
ResponseEntity<List<Product>> getAllProducts() {

<Product> Productos de lista =


[Link](); if([Link]()){
return new ResponseEntity<List<Product>>
(HttpStatus.NOT_FOUND);}<Product> Lista de
listas = nueva ArrayList<Product> ();
for(Product product:products){

[Link](producto);}volver nueva
ResponseEntity<List<Product>>(list,

[Link]);
}}

getAllProducts es un método Java que devuelve una lista de todos los productos de la
base de datos, definida mediante un protocolo abstracto y formato de entrega
declarado en el puerto REST basado en HTTP. Spring inyecta (o utiliza para
interceptar) una implementación concreta de este puerto y se utiliza en el Controlador
en tiempo de ejecución. Traducen la carga útil de datos en formato JSON

32
Capítulo 1 MiCroservices para la empresa

desde el canal de entrega HTTP hacia una llamada al método getAllProducts


en el núcleo de aplicación. Para recuperar los productos, getAllProducts
delega una llamada a una clase InMemoryDB.
El resto de la implementación del controlador REST se muestra en Listing
1-4.

Listado 1-4. Puerto HTTP basado en REST para getAllProducts (ch01\ch01-01\02-


ProductWeb\src\main\java\com\acme\ecom\product\controller\[Link]
va)

public class ProductRestController{

@RequestMapping(value = "/productsweb/{productId}",
método = [Link],produces =
MediaType.APPLICATION_JSON_VALUE)entidad
pública<Product> de respuesta getProduct(@PathVariable(
"productId") cadena productId) {Product
product = [Link](productId); if
(producto == null) {
return new <Product>ResponseEntity(
HttpStatus.NOT_FOUND);
}return new
<Product>ResponseEntity(product,
[Link]);
}@RequestMapping(valor =
"/productsweb",
método = [Link],produces =
MediaType.APPLICATION_JSON_VALUE)publica
ResponseEntity<Product> addProduct(
@RequestBody producto producto) {

33
Capítulo 1 MiCroservices para la empresa

Product ProductFound = [Link](


[Link]()); if
(null != productFound) {
return new <Product>ResponseEntity(
[Link]);
}[Link](product); return
new <Product>ResponseEntity(product,

[Link]);
}@RequestMapping(value =
"/productsweb/{productId}",
método = [Link],produces =
MediaType.APPLICATION_JSON_VALUE)entidad
pública<Product> de respuesta deleteProduct(
@PathVariable("productId")String productId)
{Product productFound = [Link](
productId); if
(productFound == null) {
return new <Product>ResponseEntity(
HttpStatus.NOT_FOUND);
}[Link](produc
tId); return new
<Product>ResponseEntity(
HttpStatus.NO_CONTENT);
}@RequestMapping(value =
"/productsweb/{productId}",
método = [Link],produces =
MediaType.APPLICATION_JSON_VALUE)publica<Pr
oduct> ResponseEntity updateProduct(
@PathVariable("productId")String
productId,@RequestBody Product product) {

34
Capítulo 1 MiCroservices para la empresa

Product currentProduct = [Link](


productId); if
(currentProduct == null) {
return new <Product>ResponseEntity(
HttpStatus.NOT_FOUND);
}[Link]([Link]());
[Link]([Link]());
[Link]([Link]());
[Link]([Link]
()); Product newProduct =
[Link](
actualProducto); return new
<Product>ResponseEntity(newProduct,
[Link]);
}}

Aquí, dado un productId, el método getProduct recuperará los detalles de


un producto específico. addProduct creará un nuevo producto y
deleteProduct eliminará un producto de la base de datos en memoria.
updateProduct actualizará un producto con un nuevo conjunto de valores.

Compila y ejecuta el código


La carpeta ch01\ch01-01 contiene los scripts Maven necesarios para compilar
y ejecutar los ejemplos. Este ejemplo es el microservicio más sencillo que
cualquiera podría imaginar, ya que no hay dependencias de recursos externos
como bases de datos o colas de mensajes. Sigue siendo un microservicio
totalmente funcional que demuestra toda la funcionalidad CRUD (Crear,
Leer, Actualizar y Eliminar), así que construir la muestra y poner en marcha
los microservicios es pan comido. Suponiendo que tengas Java y Maven
instalados en tu máquina, puedes abrir un terminal de comandos, ir a la
carpeta ch01\ch01-01 y ejecutar los comandos en la lista 1-5.

35
Capítulo 1 MiCroservices para la empresa

Listado 1-5. Comandos para construir y ejecutar el microservicio

mvn -[Link]=true clean packagejava -jar -


[Link]=8080 ./02-ProductWeb/target/Ecom-
Product- [Link]

Alternativamente, hay un script de shell para una terminal Mac y un script de


Windowsbatch que te ayudará a construir y ejecutar la aplicación de una sola
vez, como se muestra en la lista 1-6.

Listado 1-6. Compila y ejecuta el microservicio usando scripts

(base) binildass-MacBook-Pro:ch01-01 binil$


pwd/Users/binil/binil/code/mac/mybooks/docker-
04/Code/ch01/01binildass-MacBook-Pro:ch01-01 binil$ sh
[Link][INFO] Escaneando proyectos... [INFO] ------
------------------------------------------------[INFO]
Orden de Construcción del Reactor:[INFO][INFO] Ecom-
Producto-Web-Microservicio[jar][INFO] Ecom[pom][INFO]
[INFO] --------<[Link]:Ecom-Product-Web-
Micro[INFO] Construcción Ecom-Product-Web-Mi 0.0.1-
SNAPSHOT[1/2][INFO] --------------------------------[ jar
]--------------[INFO]... [INFO][INFO] Ecom-Producto-Web-
Microservicio .... ÉXITO [1.705 s][INFO]
............................. Ecom ÉXITO [0.019 s][INFO]
-----------------------------------------------------
[INFO] CONSTRUIR ÉXITO[INFO] ----------------------------
-------------------------

36
Capítulo 1 MiCroservices para la empresa

[INFO] Tiempo total:


1.902 s
[INFO] Finalizado en: 2023-12-13T11:32:38+05:30[INFO]
-----------------------------------------------------

. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \(
( )\___ | '_ | '_| | '_ \/ _` | \ \ \
\\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / /
/=========|_|==============|___/=/_/_/_/:: Spring Boot
::(v3.2.0)2023-12-13 11:32:39 INFO Inicio... :50 -
Iniciando EcomProd... 2023-12-13 11:32:39 DEBUG
[Link] -Ejecutando con Spring
Boot v3.2.0, Spring v6.1.12023-12-13 11:32:39 INFO
SpringApp... :653 - No hay activo... 2023-12-13 11:32:40
INFO [Link] - Start2023-12-13 11:32:40
INFO [Link] - Ending.2023-12-13 11:32:40
INFO Inicial... init:35 - Start2023-12-13 11:32:40
DEPURACIÓN Inicial... init:37 - No hacer nada... 2023-
12-13 11:32:40 INFO inicial....init:39 - Fin2023-12-13
11:32:40 INFO Inicio... :56 - Inicié EcomProd... 2023-
12-13 11:32:46 INFO ProdRest... getAllProducts:64 -
Start2023-12-13 11:32:46 DEPURAR ProductoRest...
lambda$getAll$0:74 -Product [productId=1, ... 2023-12-13
11:32:46 DEBUG
[Link]$getAllProducts$0:74 -
Product [productId=2, ... 2023-12-13 11:32:46 INFO
[Link] – Terminando...

Puedes ver en el registro que la aplicación está construida y desplegada, y que


está en estado de ejecución. Ahora es momento de probar la aplicación.

37
Capítulo 1 MiCroservices para la empresa

Prueba el microservicio usando la interfaz de usuario


Una vez que el microservicio está activo, puedes acceder a la aplicación web
usando tu navegador y apuntando a [Link] (véase
la Figura 1-17).

Figura 1-17. Acceso al microservicio usando un navegador

Escribir esta URL desde el navegador mostrará la aplicación UI que está


empaquetada dentro de la carpeta de recursos dentro del proyecto. Desde la
interfaz de navegador, puedes añadir un nuevo producto haciendo clic en el
botón Añadir Nuevo Producto e introduciendo los detalles (véase la Figura 1-18).

38
Capítulo 1 MiCroservices para la empresa

Figura 1-18. Añadir un nuevo producto

Introduce algunos valores significativos para todos los campos de la interfaz


y haz clic en el botón Enviar, que pedirá al microservicio que cree un nuevo
producto en la base de datos en memoria. El producto recién añadido también
aparecerá en la pantalla actualizada, como se muestra en la Figura 1-19.

39
Capítulo 1 MiCroservices para la empresa

Figura 1-19. Listado del producto recién añadido

Ahora puedes intentar editar (actualizar) el producto recién añadido


haciendo clic en el icono Editar en el lado derecho de cada entrada de
producto listado. Véase la Figura 1-20.

40
Capítulo 1 MiCroservices para la empresa

Figura 1-20. Actualizar el producto

41
Capítulo 1 MiCroservices para la empresa

Como se muestra en la Figura 1-20, sin cambiar el ID del producto, realiza


algunos cambios válidos en algunos de los campos—precio en este ejemplo. Haz
clic en el botón Enviar para que los cambios entren en vigor. Véase la Figura 1-21.

Figura 1-21. Listado del producto actualizado

Los cambios realizados en el producto se muestran en la pantalla actualizada,


como se muestra en la Figura 1-21.
Por último, pero no menos importante, quizá también quieras probar la funcionalidad
de eliminar, que puedes hacer haciendo clic en el icono de Borrar en el extremo
derecho de cada producto y luego confirmando tu acción. Véase la Figura 1-22.

42
Capítulo 1 MiCroservices para la empresa

Figura 1-22. Confirmando eliminación

Prueba el microservicio usando cURL


También puede que quieras usar cURL o Postman para probar todos
los métodos implementados en el microservicio. Consulte el Apéndice
A para instrucciones detalladas.

Resumen
En este capítulo, intenté deliberadamente evitar definir microservicios, ya que
existen muchas definiciones y puntos de vista en la industria. En cambio,
intenté analizar los microservicios desde perspectivas menos comunes para
entender cómo encajan en el paradigma informático más amplio. Este capítulo
también consideró cómo las características distintivas ayudan a proporcionar
capacidades superiores en la ejecución de transacciones comerciales. También
intenté mostrar, con ejemplos, qué es una arquitectura hexagonal. Continúo
esta discusión en los dos próximos capítulos, con más ejemplos, para que
puedas apreciar claramente la estructura de diseño y las cualidades que tendrán
tus microservicios si adoptas los principios de una arquitectura hexagonal.

43
CAPÍTULO 2

Microservicios
más prácticos
Programaste tu primer y más sencillo microservicio en el último capítulo. Ese
ejemplo usaba una estructura de datos sencilla como base de datos en memoria. Este
capítulo amplía ese ejemplo creando algunos microservicios más, cada uno en orden
creciente de complejidad. Esto te permitirá aprovechar tus aprendizajes previos.
Interactuarás con algunas bases de datos reales y reforzarás tu conocimiento de la
arquitectura de puertos y adaptadores introducida en el Capítulo 1.
Este capítulo es totalmente práctico, pero los ejemplos siguen siendo
sencillos, así que no tienes que entender relaciones empresariales o de
entidades complejas. En cambio, los ejemplos hacen hincapié en las
tecnologías de aprendizaje y las variaciones arquitectónicas.
Este capítulo cubre los siguientes conceptos, cada uno con ejemplos
en curso:

• Primero, mejorarás el ejemplo de microservicio del


capítulo anterior para interactuar con un MongoDB.

• A continuación presento la Nube de Primavera.

• Paso a una discusión sobre HAL y HATEOAS.

• Como ejemplo final, implementarás un microservicio


basado en HATEOAS usando Spring Boot.

© Binildas A. Christudas 2024B. A. Christudas, Microservicios 45


Java y contenedores en la nube,[Link]
0555-4_2
Capítulo 2 Más MiCroservices prácticos

Microservicios usando
MongoDBand RestTemplate
Como se mencionó, mejorarás el microservicio que creaste en el último capítulo.
Tendrás dos microservicios —un consumidor y un proveedor microservicio—
comunicándose entre sí usando el protocolo REST. El microservicio proveedor
también interactúa con una base de datos NoSQL, MongoDB.

Diseña los microservicios


Este ejemplo utiliza el diseño de microservicios hexagonal representado en
la Figura 1-13 del Capítulo 1. Esto se muestra de nuevo en la Figura 2-1.

Figura 2-1. Diseño de microservicios para consumidores y proveedores

Ambos microservicios mostrados en la Figura 2-1 utilizan puertos HTTP en las


interfaces theREST, que son la especificación de cómo el navegador del usuario u
otro cliente HTTP puede usar el núcleo de la aplicación. Estos puertos (interfaces)
pertenecen dentro de la lógica de negocio de los microservicios respectivos como
controladores REST. Un adaptador es proporcionado por Spring runtime, que
proporciona la funcionalidad prometida por la interfaz REST. Una petición de la

46
Capítulo 2 Más MiCroservices prácticos

El navegador accede al microservicio Product Web, que es el microservicio de


consumo. El microservicio Product Web no realiza ninguna lógica de negocio;
en su lugar, delega las llamadas al microservicio Product Server, que es el
microservicio proveedor. El objetivo de mantener el microservicio ProductWeb
sencillo es demostrar cómo iniciar comunicación entre microservicios para que
puedas usar y ampliar esta plantilla para casos del mundo real.

El RestTemplate en el microservicio Product Web es otro puerto, que de nuevo


no es más que una especificación sobre cómo lo utiliza el núcleo de la
aplicación. Un adaptador impulsado por hormigón que implementa el puerto
RestTemplate es inyectado en el núcleo de la aplicación por Spring donde y
donde sea necesario el puerto (type-hinted).
La entidad Product cumple con el núcleo de la aplicación en el
microservicio Product Server. Aquí de nuevo, evité la típica superposición
de clases estereotipo de servicio y componente para mantener la
complejidad general del ejemplo simple.
ProductRepository es el tercer puerto utilizado por el microservicio Product
Server. El propósito del microservicio Product Server es persistir datos. Así
que creas una interfaz de persistencia que satisfaga sus necesidades, con
métodos para realizar operaciones CRUD en una colección NoSQL usando el
ID de la entidad. En ese momento, siempre y donde la aplicación necesite
ejecutar operaciones CRUD, el núcleo de la aplicación necesitará un objeto
que implemente la interfaz de persistencia que definiste, que es suministrada
por el runtime de Spring.

Organización del código


El código fuente de este libro está disponible en GitHub a través de la página
de producto del libro, ubicada en [Link]/9798868805547. El
código del ejemplo está organizado como se muestra en la Lista 2-1, dentro
de la carpeta ch02\ch02-01. Esto sigue la estructura estándar de Maven, por lo
que [Link] está en la raíz del directorio.

47
Capítulo 2 Más MiCroservices prácticos

Listado 2-1. Organización del código fuente de Spring Boot

├── 01-ProductServer│├── [Link]│└── src│└── main│├──


java││└── com││└─ acme││└── ecom││└── product││├──
[Link]││├├─ Product│├│├─ ││├├│
[Link]││├── Controlador│││└──
[Link]││├── Modelo│││└── [Link]││└─
Repositorio││├── [Link]││└──
[Link]│└─ Recursos│├── Aplicación.1││─
Aplicació[Link]│└── [Link]├── 02-
ProductWeb│├── [Link]│└── SRC│└── Main│├── Java││└─
Com││└── ACME││└── ecom││└─ Producto

48
Capítulo 2 Más MiCroservices prácticos

││├── [Link]││├── [Link]││├──


Controlador││├── [Link]│││└──
[Link]││└─ Modelo││├── [Link]││└─
[Link]│└─ Recursos│├──
Aplicació[Link]│├── [Link]│└──
Estática│├── CSS││├── [Link]││└── [Link]│├──
JS││├── [Link]││├── Controlador││└──
product_controller.js││└─ Servicio││└──
product_service.js│└── [Link]└── [Link]

Ten en cuenta que los nombres de algunas de las clases Java


en el Listado 2-1 han sido acortados por motivos de formato.

La carpeta ch02\ch02-01 contiene el código fuente para los microservicios de


consumo y proveedor. La carpeta superior también contiene scripts que te
ayudarán a construir los microservicios juntos. También hay scripts en esta
carpeta para limpiar los proyectos al final.

49
Capítulo 2 Más MiCroservices prácticos

Entendiendo el Código
Veamos primero el microservicio del proveedor —el microservicio Product
Server—. La lista 2-2 comienza con el puerto HTTP compatible con REST,
usando un SpringRestController.

Listado 2-2. Puerto HTTP basado en REST para getAllProducts ProductServer (ch02\ch02-01\01-
ProductServer\src\main\java\com\acme\ecom\product\controller\[Link])

@RestControllerpublic class
ProductRestController {

@Autowiredprivate Repositorio de
productos repositorio;
@RequestMapping(valor = "/productos",
método = [Link],produces =
{MediaType.APPLICATION_JSON_VALUE})Public
ResponseEntity<List<Product>> getAllProducts() {

<Product> Productos de la lista =


[Link](); if([Link]()){
volver nuevo ResponseEntity<List<Product>>(
HttpStatus.NOT_FOUND);
}<Product>Lista lista = nueva
ArrayList<Product> (); for(Product
product:products){
[Link](producto);}[Link](item-
>[Link]([Link]())); volver nueva
ResponseEntity<List<Product>>(list,

[Link]);
}}

50
Capítulo 2 Más MiCroservices prácticos

getAllProducts es un método Java que devuelve una lista de todos los


productos en la base de datos MongoDB, definida mediante un protocolo
abstracto y el formato de entrega declarado en el puerto REST basado en
HTTP. A continuación, se inyecta (o se utiliza para interceptar) una
implementación concreta de este puerto bySpring y se utiliza en el borde del
controlador en tiempo de ejecución. Traducen la carga útil de datos de solicitud
en formato JSON desde el canal de entrega HTTP a una llamada al método
getAllProducts en el núcleo de la aplicación. Para recuperar los productos,
getAllProducts delega llamadas al puerto controlado, ProductRepository.
El resto de la implementación del controlador REST en el microservicio
Product Server es muy similar al código del Listado 1-4 en el Capítulo 1 (con
la única excepción de que, en lugar de la base de datos en memoria, el puerto
ProductRepository se usa para interactuar con un repositorio MongoDB), por
lo que no repito el código completo aquí.
Este ejemplo introduce el puerto abstracto para interactuar con el
MongoDB, como se muestra en el Listado 2-3.

Listado 2-3. Puerto abstracto al Repositorio MongoDB (ch02\ch02-01\01-


ProductServer\src\main\java\com\acme\ecom\product\repository\Product
[Link])

@RepositoryRestResource(collectionResourceRel =
"productdata", path = "productdata") interfaz pública
ProductRepository extends
MongoRepository<Product, String>
{public<Product> List findByCode(
@Param("código") Código de
cadena);}

Dado que este puerto extiende MongoRepository, todas las declaraciones


predeterminadas de CRUDmethod se heredan por defecto. Por lo tanto, solo
necesitas declarar los métodos personalizados—findByCode en este ejemplo.

51
Capítulo 2 Más MiCroservices prácticos

El código para la clase principal del microservicio Product Server se


muestra en el Listado 2-4.

Listados 2-4. Clase principal de Microservicio Product Server


(ch02\ch02-01\01-ProductServer\src\main\java\com\acme\ecom\product
\[Link])

@SpringBootApplicationpublic clase
EcomProductMicroserviceApplication {

empty estático público main(String[] args) {

[Link](
[Link], args);
}}

En los listados 2-5 se muestra el archivo de configuración de microservicios de


Product Server.
Listados 2-5. El archivo de configuración de microservicios del
Product Server (ch02\ch02-01\01-
ProductServer\src\main\resources\[Link])

[Link]=mongodb://localhost:27017
/[Link]=[Link] =
product-server

Esta URL apunta a la base de datos de MongoDB. A continuación, verás el


microservicio para consumidores, es decir, el microservicio ProductWeb. En
las listas 2-6 se muestra el puerto HTTP compatible con REST, usando un
Spring RestController.

52
Capítulo 2 Más MiCroservices prácticos

Listados 2-6. Puerto HTTP basado en REST para getAllProducts Product Web (ch02\ch02-
01\02-
ProductWeb\src\main\java\com\acme\ecom\product\controller\[Link])

@RestControllerpublic class
ProductRestController{

@Value("${acme. PRODUCT_SERVICE_URL}")privado
String PRODUCT_SERVICE_URL;@Autowiredprivate
RestTemplate
restTemplate;@RequestMapping(value =
"/productsweb",
método = [Link],produces =
{MediaType.APPLICATION_JSON_VALUE})Public
ResponseEntity<List<Product>> getAllProducts() {

ReferenciaDeTipo<Lista<Product>>
responseTypeRep = nueva ParameterizedTypeReference<
List<Product>>() {};
EntidadRespuesta<Lista<Product>> entidad =
[Link](PRODUCT_SERVICE_URL,
[Link], (<Product>HttpEntity)
null,responseTypeRef);
List<Product> productList = [Link](); return
new ResponseEntity<<Product>List>(productList,
[Link]);
}}

El valor de PRODUCT_SERVICE_URL está configurado en


[Link] para apuntar a la URL del microservicio
del proveedor, de la siguiente manera: acme.
PRODUCT_SERVICE_URL = [Link]
53
Capítulo 2 Más MiCroservices prácticos

El adaptador para realizar la comunicación entre microservicios está definido


en el microservicio Web del Producto definiendo el RestTemplateconfigured
en Spring en la clase de configuración, como se muestra en el Listado 2-7.

Listados 2-7. Configuración de plantilla REST en Product Web ch02\ch02-01\02-


ProductWeb\src\main\java\com\acme\ecom\product\controller\ProductRestContr
[Link])

@Frijol
RestTemplate restTemplate() {
ObjectMapper mapper = nuevo
ObjectMapper(); [Link](
Característica de deserialización.FAIL_ON_UNKNOWN_PROPERTIES,
falso);
MappingJackson2HttpMessageConverter converter =
nuevo MappingJackson2HttpMessageConverter();
[Link](
[Link]("application/json"));
[Link](mapper); return new
RestTemplate([Link](converter));}}

A partir de ahora, siempre que el microservicio Web de Producto necesite


comunicarse con la API externa del microservicio del Servidor de Producto,
necesitas un objeto que implemente la interfaz RestTemplate que definiste, y
Spring te lo proporciona.
El resto de la implementación del microcontrolador de microservicios
RESTcontroller de la Web del Producto se muestra en la Lista 2-8.

54
Capítulo 2 Más MiCroservices prácticos

Listados 2-8. Puerto HTTP basado en REST para métodos CRUD de ProductWeb (ch02\ch02-
01\02-
ProductWeb\src\main\java\com\acme\ecom\product\controller\[Link])

public class ProductRestController{

@RequestMapping(value = "/productsweb/{productId}",
método = [Link],produces =
MediaType.APPLICATION_JSON_VALUE)entidad
pública<Product> de respuesta getProduct(@PathVariable(
"productId") String productId) {String uri =
PRODUCT_SERVICE_URL + "/" + productId; Product
product = [Link](uri,
[Link]); return new
<Product>ResponseEntity(product,
[Link]);
}@RequestMapping(valor =
"/productsweb",
método = [Link],produces =
MediaType.APPLICATION_JSON_VALUE)publica
ResponseEntity<Product> addProduct(
@RequestBody producto producto) {producto
producto nuevo = [Link](
PRODUCT_SERVICE_URL,producto,
[Link]); return new
<Product>ResponseEntity(product,
[Link]);
}@RequestMapping(value =
"/productsweb/{productId}",
método = [Link],produces =
MediaType.APPLICATION_JSON_VALUE)

55
Capítulo 2 Más MiCroservices prácticos

public<Product> ResponseEntity
deleteProduct(@PathVariable("productId")String productId) {

[Link](PRODUCT_SERVICE_URL + "/" +
productId); return new
<Product>ResponseEntity(
HttpStatus.NO_CONTENT);
}@RequestMapping(value =
"/productsweb/{productId}",
método = [Link],produces =
MediaType.APPLICATION_JSON_VALUE)publica<Pr
oduct> ResponseEntity updateProduct(
@PathVariable("productId")String
productId,@RequestBody Product product) {String uri
= PRODUCT_SERVICE_URL + "/" + productId;
[Link](uri, product, [Link]);
Product updatedProduct = [Link](
uri, [Link]); return new
<Product>ResponseEntity(updatedProduct,
[Link]);
}}

Dado un productId, el método getProduct recuperará los detalles de un


producto específico. addProduct creará un nuevo producto y deleteProductará
eliminará un producto de la base de datos de MongoDB. actualiza el producto
actualiza un producto con un nuevo conjunto de valores.

56
Capítulo 2 Más MiCroservices prácticos

Construye y ejecuta el microservicio


La carpeta ch02\ch02-01 contiene los scripts Maven necesarios para
construir estos ejemplos. Como primer paso, necesitas abrir el servidor de
MongoDB. Consulta el Apéndice B para aprender a configurar un servidor
MongoDB y ponerlo en marcha. Necesitas ejecutar los comandos que
aparecen en los listados 2-9 para abrir MongoDB.

Listados 2-9. Abriendo el servidor MongoDB

(Base) binildas-MBP:Bin Vinil$pued/Users/Vinil/APLNS/Mangadab/Mangadab-


macOS-x86_64-4.2.8/Bin(Base) Binildas-MBP:Bin Vinil$Mangad --
dbpith/usr/local/var/mangdab --logpath/usr/local/var/log/mangadab/[Link]

Después, abre un terminal de comandos y ve a la carpeta ch02\ch02-01.


Ejecuta los comandos mostrados en la lista 2-10 para construir los
microservicios juntos.

Listado 2-10. Construcción y funcionamiento de los microservicios

(base) binildass-MBP:ch02-01 binil$


pwd/Usuarios/binil/binil/code/mac/mybooks/docker-
03/ch02/ch02-01binildass-MacBook-Pro:ch02-01 binil$
sh [Link][INFO] Escaneando proyectos... [INFO] -----
-----------------------------------------------[INFO]
Orden de construcción del reactor:[INFO][INFO] Ecom-
Producto-Servidor-Microservicio[jar][INFO] Ecom-
Producto-Web-Microservicio[jar][INFO] Ecom[pom]
[INFO]... [INFO]

57
Capítulo 2 Más MiCroservices prácticos

[INFO] Ecom-Producto-Servidor-Microservicio ÉXITO [


1.834 s][INFO] Ecom-Producto-Web-Microservicio ...
ÉXITO [ 0,425 s][INFO] E-COME
............................ ÉXITO [ 0,040 s][INFO] --
---------------------------------------------------
[INFO] BUILD ÉXITO[INFO] -----------------------------
------------------------[INFO] Tiempo total: 2,491
s[INFO] Finalizado en: 2023-12-20T08:26:08+05:30[INFO]
-----------------------------------------------------
binildass-MacBook-Pro:ch02-01 binil$

Alternativamente, puedes tomar dos terminales de comandos y cambiar el


directorio a la carpeta de nivel superior de los microservicios. Primero,
compila y ejecuta el microservicio Product Server usando los scripts [Link]
y [Link], como se muestra en la Lista 2-11.

Listado 2-11. Construcción y ejecución del Microservicio


Product Server usando scripts

(base) binildass-MacBook-Pro:01-ProductServer binil$


pwd/Users/binil/binil/code/mac/mybooks/docker-
03/ch02/ch02-01/01-ProductServerbinildass-MacBook-
Pro:01-ProductServer binil$ sh [Link][INFO] Escaneando
proyectos... [INFO]... [INFO] --------------------------
--------------------------[INFO] ÉXITO DE BUILD[INFO] --
--------------------------------------------------[INFO]
Tiempo total:2.136 s[INFO] Finalizado en: 2023-12-
20T08:18:18+05:30[INFO] --------------------------------
--------------------binildass-MacBook-Pro:01-
ProductServer binil$

58
Capítulo 2 Más MiCroservices prácticos

binildass-MacBook-Pro:01-ProductServer binil$ sh [Link]

. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \(
( )\___ | '_ | '_| | '_ \/ _` | \ \ \
\\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / /
/=========|_|==============|___/=/_/_//:: Bota de
muelle ::(v3.2.0)2023-12-20 08:21:18 INFO [Link]
- Iniciando EcomProd... 2023-12-20 08:21:18 DEPURACIÓN
[Link] - Ejecutar con arranque v3.2.02023-12-20
08:21:18 INFO [Link] - No activa ... 2023-
12-20 08:21:19 INFO [Link] - Start2023-
12-20 08:21:19 INFO [Link] - End2023-12-
20 08:21:20 INFO [Link] - Iniciado EcomProd...

A continuación, construye y ejecuta el microservicio Web de


Producto, como se muestra en Listing 2-12.

Listado 2-12. Construcción y ejecución del microservicio web del


producto Usando scripts

(base) binildass-MacBook-Pro:02-ProductWeb binil$


pwd/Users/binil/binil/code/mac/mybooks/docker-
03/ch02/ch02-01/02-ProductWebbinildass-MacBook-Pro:02-
ProductWeb binil$ sh [Link]... binildass-MacBook-
Pro:02-ProductWeb binil$ sh [Link][INFO] Escaneando
proyectos... [INFO]... 2023-12-20 08:23:46 INFO
[Link] - No activo ... 2023-12-20 08:23:47
INFO [Link] - Inicio

59
Capítulo 2 Más MiCroservices prácticos

2023-12-20 08:23:47 DEBUG [Link] - No hacer


nada2023-12-20 08:23:47 [Link] -
Fin2023-12-20 08:23:47 [Link]
-Iniciado EcomProduct...

Ahora que ambos microservicios están operativos, puedes probar los


microservicios.

Pruebas de los microservicios


Una vez que ambos microservicios estén operativos, puedes inspeccionar tu
servidor MongoDB usando la terminal Mongo para asegurarte de que el
microservicio del Product Server ha insertado algunos productos en el servidor
MongoDB durante el arranque del microservicio (véase la Lista 2-13).
Consulta el Apéndice B para aprender a usar el terminal Mongo.

Listado 2-13. Inspección del servidor MongoDB usando un shell Mongo

> mostrar coleccionesproducto> bases de datos.


[Link](){ "_id" :
ObjectId("619e1a5b21b6e123a375641c"), "name" :"Kamsung
D3", "code" : "KAMSUNG-TRIOS", "title" : "KamsungTrios 12
pulgadas, negro, 12 px ....", "precio" : 12000, "_class":
"[Link]" }{ "_id" :
ObjectId("619e1a5b21b6e123a375641d"), "name" :
"LokiaPomia", "code" : "LOKIA-POMIA", "title" : "Lokia 12
pulgadas, blanco, 14px ....", "precio" : 9000, "_class" :
"[Link]" }>

Cuando todo esté listo, puedes acceder a la aplicación web usando tu


navegador y apuntando a [Link]

60
Capítulo 2 Más MiCroservices prácticos

Para probar las operaciones CRUD, siga las instrucciones descritas en la


subsección "Probar los microservicios usando la interfaz de usuario" en la
última sección del Capítulo 1, titulado "Su primer microservicio en Java."

Microservicios que utilizan Spring Cloud


Spring Cloud está construido sobre Spring Boot. Spring Cloud ofrece
muchos patrones comunes en ecosistemas de microservicios distribuidos que
pueden ayudarte a integrar los servicios principales como un conjunto de
servicios débilmente acoplados. SpringCloud también ofrece muchas
herramientas potentes que mejoran el comportamiento de las aplicaciones
Spring Boot para implementar esos patrones. Esta sección muestra uno de
estos patrones con código para que puedas apreciar los beneficios que ofrece.

Diseña los microservicios


Esta sección modifica ligeramente el ejemplo anterior de
microservicios para introducir Spring Cloud.

Figura 2-2. Diseño de microservicios con cliente Spring Cloud Feign

61
Capítulo 2 Más MiCroservices prácticos

Como se explicó en el ejemplo anterior, en ambos microservicios mostrados


en la Figura 2-2, se usan puertos HTTP en las interfaces REST, que
especifican cómo el navegador del usuario u otro cliente HTTP puede usar el
núcleo de la aplicación. Estos puertos (interfaces) pertenecen dentro de la
lógica de negocio de los microservicios respectivos como controladores
REST. Las solicitudes del navegador accederán al microservicio Product
Web, que es el microservicio para consumidores. El microservicio Product
Web no realiza ninguna lógica de negocio; en su lugar, delega llamadas al
microservicio Product Server, el proveedor microservicio.
El puerto FeignClient en el microservicio Product Web es anotherport, que
de nuevo no es más que una especificación de cómo lo utiliza el núcleo de
la aplicación. Un adaptador impulsado por hormigón que implementa el
puerto FeignClient es inyectado en el núcleo de la aplicación por Spring
Cloud, donde sea y donde sea necesario el puerto (type-hinted).
La entidad Product cumple con el núcleo de la aplicación en el
microservicio Product Server.
El resto de los puertos y adaptadores en el microservicio Product Server
funcionan exactamente igual que en el ejemplo anterior.

Entendiendo el Código
El código fuente de este libro está disponible en GitHub a través de la
página de producto del libro, ubicada en [Link]/9798868805547.
El código fuente de este ejemplo está organizado dentro de la carpeta
ch02\ch02-02. El código fuente es similar al ejemplo anterior. El
microservicio Product Server es similar; sin embargo, hay algunos cambios
en los microservicios de ProductWeb, que puedes consultar aquí. En lugar
de la PlantillaRest, este ejemplo utiliza FeignClient. El listado 2-14 muestra
cómo especificar FeignClient.

62
Capítulo 2 Más MiCroservices prácticos

Listado 2-14. La interfaz de servicio para el Microservicio Product Server


(ch02\ch02-02\02-
ProductWeb\src\main\java\com\acme\ecom\product\api\[Link])

interfaz pública ProductService {

@RequestMapping(valor = "/productos",
método = [Link],produce =
MediaType.APPLICATION_JSON_VALUE)Public
ResponseEntity<Resources<Resource<Product>>>
getAllProducts();@RequestMapping(value =
"/products/{productId}",
método = [Link],produces =
MediaType.APPLICATION_JSON_VALUE)Public
ResponseEntity<Resource<Product>> getProduct(
@PathVariable("productId") Cadena
productId);@RequestMapping(valor = "/productos",
método = [Link],produces =
MediaType.APPLICATION_JSON_VALUE)Public
ResponseEntity<Resource<Product>> addProduct(
@RequestBody Producto producto);@RequestMapping(valor
= "/productos/{productId}",
método = [Link],produce =
MediaType.APPLICATION_JSON_VALUE)Public
ResponseEntity<Resource<Void>> deleteProduct(
@PathVariable("productId") Cadena
productId);@RequestMapping(value = "/products/{productId}",
método = [Link],produces =
MediaType.APPLICATION_JSON_VALUE)

63
Capítulo 2 Más MiCroservices prácticos

públicoResponseEntity<Resource<Product>> updateProduct(
@PathVariable("productId") String productId
,@RequestBody producto producto);}

Lo primero que harás aquí es definir una interfaz de servicio, como se


muestra en Listing 2-14. A partir de esta interfaz de servicio, puedes declarar
un abstractFeignClient, que es un cliente de servicio web declarativo. Lo
bueno de usar Feign es que no tienes que escribir ningún código para llamar a
theservice, salvo una definición de interfaz, como se muestra en la Lista 2-15.

Listado 2-15. La interfaz cliente fingida para el Microservicio Product Server (ch02\ch02-
02\02-ProductWeb\src\main\java\com\acme\ecom\product\client\[Link])

@FeignClient(name="the-name", url =
"[Link] pública
ProductServiceProxy extiende ProductService{}

Se debe especificar un nombre para todos los clientes, que es el nombre


del servicio con el prefijo opcional de protocolo.
Luego declaras a este Cliente Feign en [Link], como se muestra
en Listing 2-16.

Listado del 2 al 16. La dependencia fingida del cliente en


Maven (ch02\ch02-02\02-ProductWeb\[Link])

<dependencies>

<groupId>[Link]</grou
pId><artifactId>
primavera-nube-iniciador-
openfeign</artifactId>

64
Capítulo 2 Más MiCroservices prácticos

<version>4.1.0</version>
</dependency></dependencies>

Puedes usar las propiedades de la aplicación para configurar clientes Feign; sin
embargo, mantengo este ejemplo simple, sin configurar el cliente Feign con
tales detalles. Véase el Listado 2-17.

Listado 2-17. La configuración de la cinta (ch02\ch02-02\02-


ProductWeb\src\main\resources\[Link])

Fingi:
Cliente:C
onfig:
Por defecto:
connectTiempo de espera:
5000readTiempo de salida:
5000loggerNivel: básico

Construye y ejecuta el microservicio


La carpeta ch02\ch02-02 contiene los scripts Maven necesarios para
construir los ejemplos. Como primer paso, necesitas abrir el servidor de
MongoDB. Consulta el Apéndice B para aprender a configurar un servidor
MongoDB y activarlo. Tienes que ejecutar los comandos que aparecen en
la lista 2-18 para activar MongoDB.

Listado 2-18. Abriendo el servidor MongoDB

(Base) binildas-MBP:Bin
Vinil$pued/Users/Vinil/APLNS/Mangadab/Mangadab-macOS-x86_64-
4.2.8/Bin(Base) Binildas-MBP:Bin Vinil$Mangad --
dbpith/usr/local/var/mangdab --
logpath/usr/local/var/log/mangadab/[Link]

65
Capítulo 2 Más MiCroservices prácticos

A continuación, toma dos terminales de comandos y cambia el directorio a la


carpeta de nivel superior de ambos microservicios. Luego, compila y ejecuta
el microservicio ProductServer usando los scripts [Link] y [Link], como se
muestra en Listing 2-19.

Listado 2-19. Compilar y ejecutar microservicio del servidor


de producto usando scripts

(base) binildass-MacBook-Pro:01-ProductServer binil$


pwd/Users/binil/binil/code/mac/mybooks/docker-
04/Code/ch02/ch02-02/01-ProductServer(base) binildass-
MacBook-Pro:01-ProductServer binil$ sh [Link][INFO]
Escaneando proyectos... [INFO]... 2023-12-20 09:28:00
INFOInitializació[Link] - Inicio23-12-20 09:28:01
INFOInitializació[Link] - Fin2023-12-20 09:28:01
[Link] - Inicié EcomProd...

Como siguiente paso, construye y ejecuta el microservicio Product Web,


como se muestra en el Anuncio 2-20.

Listado 2-20. Compilar y ejecutar microservicio web de


producto Usando scripts

(base) binildass-MacBook-Pro:02-ProductWeb binil$


pwd/Users/binil/binil/code/mac/mybooks/docker-
04/Code/ch02/ch02-02/02-ProductWeb(base) binildass-
MacBook-Pro:02-ProductWeb binil$ sh [Link][INFO]
Escaneando proyectos......

66
Capítulo 2 Más MiCroservices prácticos

2023-12-20 09:32:00 INFO [Link] - Start2023-12-


20 09:32:00 DEBUG [Link] - No hacer nada.2023-
12-20 09:32:00 INFO [Link] - Fin2023-12-
2009:32:00 INFO [Link] - Inicié EcomProduct...

Ahora que ambos microservicios están operativos, puedes probar los


microservicios.

Pruebas de los microservicios


Una vez que ambos microservicios estén operativos, puedes acceder a la
aplicación web usando tu navegador. Apunta a esta URL:
[Link]

Para probar las operaciones CRUD, siga las instrucciones descritas en la


subsección "Probar los microservicios usando la interfaz de usuario" en la
última sección del Capítulo 1, titulado "Su primer microservicio en Java."
Ahora que has experimentado el sabor de Spring Boot y SpringCloud, la
siguiente sección aborda otro concepto importante en microservicios
basados en REST: HATEOAS y HAL.

HATEOAS y HAL
La hipermedia como motor de estado de aplicación (HATEOAS) es una
restricción de la arquitectura de la aplicación REST, que desacopla el cliente
del servidor. Este desacoplamiento permite que la funcionalidad del servidor
evolucione de forma independiente. La siguiente sección investiga esto más a
fondo, de nuevo con ejemplos prácticos.

67
Capítulo 2 Más MiCroservices prácticos

HATEOAS Explicado
HATEOAS defiende un agente de usuario que implementa HTTP para realizar una
solicitud HTTP de una API REST a través de una URL simple. Una vez bootstrapada,
todas las solicitudes posteriores que el agente de usuario pueda hacer se encuentran
dentro de las respuestas a cada solicitud. Los tipos de medios utilizados para estas
representaciones, y las relaciones de enlace que puede contener cada respuesta, están
estandarizados. El cliente realiza la transición a través de los estados de la aplicación
seleccionando entre los enlaces dentro de una representación o manipulando la
representación de otras formas que permite su tipo de medio. En otras palabras, se
descubren los recursos disponibles y las acciones aplicables a estos recursos, y las
transiciones posteriores se orquestan en consecuencia. De este modo, RESTfulinteraction
está impulsada por la hipermedia, en lugar de información fuera de banda.
Por ejemplo, la solicitud GET en el Listado 2-21 obtiene un producto-
recurso, solicitando detalles en una representación JSON.

Listado 2-21. Formato de respuesta de HATEOAS

GET /productdata/61a7a51467964f330f6560fa
HTTP/1.1Host: [Link]{

"productId" :
"61a7a51467964f330f6560fa","name": "Lokia
Pomia", "code": "LOKIA-POMIA", "título":
"Lokia 12 pulgadas, blanco, 14px
....","precio" : 9000.0,"_links" : {

"yo" : {
"href" :
"[Link]

68
Capítulo 2 Más MiCroservices prácticos

"producto" : {
"href" :
"[Link] : "
[Link]

La respuesta contiene el enlace de seguimiento para comprar el producto. Más


adelante, cuando el stock de este SKU de producto es cero, el enlace
"Comprar" puede no estar disponible, o para reformularlo, en su estado actual,
el enlace de Compra no está disponible. De ahí el término Motor de Estado de
Aplicación. Las acciones posibles varían según el estado del recurso.
HATEOS proporciona así respuestas basadas en el contexto usando
hipermediacontrols, que indican qué operaciones son posibles, o, en ese caso,
no posibles, basándose en la presencia o ausencia de estos enlaces. Esto ayuda a
evitar transportar campos relacionados con el estado entre servidores y clientes.

HAL explicado
El Lenguaje de Aplicaciones de Hipertexto (HAL) es una convención estándar
de Internet (un "trabajo en progreso") para definir hipermedios, como enlaces
a recursos externos dentro de datos JSON o XML. HAL está estructurado para
representar elementos basados en los conceptos de Recursos y Enlaces. Los
recursos consisten en enlaces URI, recursos embebidos, tus datos estándar
JSON o XML y enlaces no URI. Los enlaces tienen un URI objetivo, el
nombre del enlace (referido como asrel) y propiedades opcionales diseñadas
para tener en cuenta la deprecación y la negociación de contenido.
En resumen, el modelo HAL gira en torno a dos conceptos sencillos.

• Recursos que contienen:

• Enlaces a URIs relevantes

69
Capítulo 2 Más MiCroservices prácticos

•Recursos integrados
•Estado

•Enlaces:

•Un URI objetivo

•Una relación, o rel, con el enlace

•Algunas otras propiedades opcionales para ayudar con la depreciación,


negociación de contenido, etc. Con esa pequeña introducción, ahora
puedes entrar en acción con algo de código.

Microservicios que utilizan HATEAOS y HAL


Esta sección utiliza un ejemplo práctico para mostrar cómo encajan las
cosas. Modificarás el ejemplo de microservicios para demostrar tanto
HATEOAS como HAL.

Diseña los microservicios


Este ejemplo reutiliza la vista de microservicios hexagonal mostrada en la Figura
2-1 y descrita anteriormente. Algunas de las diferencias son las siguientes:

• El microservicio Web de Producto se mejorará para


mostrar la capacidad HATEOAS.

• El microservicio Product Server se mejorará para demostrar HAL.


Aprovecharás el proyecto HATEOAS de primavera para crear servicios web
REST impulsados por hipermedia. La intención es crear fácilmente
representaciones REST que sigan el principio de HATEOAS para que la API
pueda guiar al cliente a través de la aplicación devolviendo información
relevante sobre los siguientes pasos posibles, junto con cada respuesta.

70
Capítulo 2 Más MiCroservices prácticos

Organización del código


El código fuente de este libro está disponible en GitHub a través de la página
de producto del libro, ubicada en [Link]/9798868805547.. El código
de este ejemplo está organizado como se muestra en la lista 2-22, dentro de la
carpeta ch02\ch02-03. Esto sigue la estructura estándar de Maven, por lo que
[Link] está en la raíz del directorio. Se muestra la organización del código
solo para la parte relevante del microservicio ProductWeb, ya que ya viste el
código del microservicio de ProductServer.

Listado 2-22. Organización del código fuente de Spring Boot

.├── 01-ProductServer│├── ... ├── 02-ProductWeb│├──


[Link]│└── src│└── main│├── java││└── com││└─ acme││└──
ecom││└── Producto││├── [Link]││├──
[Link]││├── Controlador││──
[Link]││├── Hateoas│││└── Modelo│││└─
[Link]

71
Capítulo 2 Más MiCroservices prácticos

││ └── modelo
││ └── [Link]
│ └── Recursos
└── [Link]

Una diferencia que quieres destacar es la subcarpeta hateoas en el modelo


de entidad Producto. Explicaré el motivo de esta carpeta en la siguiente
sección.

Entendiendo el Código
Veamos primero los cambios en el microservicio del proveedor — el
microservicio Product Server.
Gran parte de la implementación del controlador REST en el microservicio
ProductServer es similar al código de los Listados 1-3 y 1-4 en el Capítulo 1,
con la excepción de que, en lugar de la base de datos en memoria, los puertos
ProductRepository y ProductCategoryRepository se usan para interactuar con
un repositorio MongoDB, por lo que no repito el código completo aquí. Sin
embargo, este ejemplo introduce un navegador HAL. El navegador HAL fue
creado por la misma persona que desarrolló HAL y ofrece una interfaz gráfica
de navegador para navegar por tu API REST. Es fácil integrar un
HALbrowser en tu proyecto Maven añadiendo la dependencia
correspondiente—véase Listado 2-23.

Listado 2-23. Dependencia del navegador HAL en Maven


(ch02\ch02-03\01-ProductServer\[Link])

<dependencies>

<groupId>[Link]</groupId>
<artifactId>spring-data-rest-hal-explorer</artifactId>
</dependency></dependencies>

72
Capítulo 2 Más MiCroservices prácticos

Hay algunos cambios en el microservicio Product Web, y los


comentaré. El listado 2-24 muestra la variante HATEOAS de la
entidad Producto.

Listado 2-24. Variante HATEOAS de la entidad producto (ch02\ch02-03\02-


ProductWeb\src\main\java\com\acme\ecom\product\hateoas\model\Product.
java)
clase pública El producto extiende el Modelo<Product> de Representación {

producto privado de
String; nombre privado
String; código de cadena
privado;; título privado
de String; privado Doble
precio;}

El Producto se extiende desde la clase Representation Model hasta heredar


el método add(). Una vez que creas un enlace, puedes asignar ese valor
fácilmente a la representación del recurso sin añadir nuevos campos.
A continuación, veamos los métodos de clase Controlador. El código en
Listing 2-25 muestra cómo construir hipervínculos HATEOAS basados
en el método thegetProduct() del ProductRestController.

Listado 2-25. Controlador REST HATEOAS (ch02\ch02-03\02-


ProductWeb\src\main\java\com\acme\ecom\product\controller\Product
[Link])

public class ProductRestController{

private static final Logger LOGGER =


[Link]([Link]
ss);@Value("${acme. PRODUCT_SERVICE_URL}")privado
String PRODUCT_SERVICE_URL;

73
Capítulo 2 Más MiCroservices prácticos

@Autowiredpublic RestTemplate
restTemplate;@Autowiredprivate ModelMapper
modelMapper;@RequestMapping(value =
"/productsweb/{productId}",

método = [Link],produces =
MediaType.APPLICATION_JSON_VALUE)public
ResponseEntity<[Link].P
roduct>
getProduct(@PathVariable("productId")
String productId) {

String uri = PRODUCT_SERVICE_URL + "/" + productId;


[Link] product Retreived =
[Link](uri,
[Link]);
[Link]
productHateoas = convertEntityToHateoasEntity(
productoRecuperado);
[Link](linkTo(methodOn(
[Link]).getProduct(produc
[Link]())).withSelfRel());
volver nueva ResponseEntity<
[Link]>(
productHateoas, [Link]);
}privado
[Link]
convertirEntityToHateoasEntity(
[Link] product){
return [Link](

74
Capítulo 2 Más MiCroservices prácticos

producto,
[Link].
modelo. [Link]);
}}

WebMvcLinkBuilder ofrece un gran soporte para controladores Spring


MVC. El métodoOn() obtiene el mapeo del método haciendo invocaciones
ficticias del método destino en el controlador proxy y establece
theproductId como variable de camino del URI.
WebMvcLinkBuilder también simplifica la construcción de URIs al evitar
codificar los enlaces de forma fija. El código en la Lista 2-25 muestra cómo
construir el enlace productoself-enlace usando la clase WebMvcLinkBuilder.
Usas el ModelMapper para mapear implícitamente una instancia de producto HATEOAS a
una instancia de Product API que no sea HATEOAS. Cuando se llama al método de mapa,
se analizan los tipos fuente y destino para determinar qué propiedades coinciden
implícitamente. Los datos se mapean según estas coincidencias. Incluso cuando los
objetos fuente y destino y sus propiedades son diferentes, ModelMapper puede hacer
todo lo posible por determinar coincidencias razonables entre propiedades si existe
una estrategia de emparejamiento configurada.

De nuevo, para abreviar, no incluyo el resto de métodos para


theProductRestController. Puedes consultarlos en el repositorio de código.

Construye y ejecuta el microservicio


La carpeta ch02\ch02-03 contiene los scripts Maven necesarios para
construir los ejemplos. Como primer paso, necesitas abrir el servidor de
MongoDB. Consulta el Apéndice B para aprender cómo configurar el
servidor MongoDB y activarlo. Necesitas ejecutar los comandos que
aparecen en la lista 2-26 para abrir MongoDB.

75
Capítulo 2 Más MiCroservices prácticos

Listado del 2 al 26. Abriendo el servidor MongoDB

(Base) binildas-MBP:Bin Vinil$pued/Users/Vinil/APLNS/Mangadab/Mangadab-


macOS-x86_64-4.2.8/Bin(Base) Binildas-MBP:Bin Vinil$Mangad --
dbpith/usr/local/var/mangdab --
logpath/usr/local/var/log/mangadab/[Link]

A continuación, toma dos terminales de comandos y cambia el directorio a


la carpeta de nivel superior de ambos microservicios. Compila y ejecuta el
microservicio Product Server usando los scripts [Link] y [Link], como se
muestra en Listing 2-27.

Listado 2-27. Compilar y ejecutar microservicio del servidor


de producto usando scripts

(base) binildass-MBP:01-ProductServer binil$


pwd/Users/binil/binil/code/mac/mybooks/docker-
03/ch02/ch02-03/01-ProductServer(base) binildass-MBP:01-
ProductServer binil$ sh [Link][INFO] Escaneando
proyectos... [INFO]... 2023-12-20 10:33:45
[Link] - Start2023-12-20 10:33:45
[Link] - Fin2023-12-20 10:33:45
[Link] - Iniciado EcomProd...

A continuación, construye y ejecuta el microservicio Product Web,


como se muestra en Listing 2-28.

76
Capítulo 2 Más MiCroservices prácticos

Listado del 2 al 28. Compilar y ejecutar microservicio


web de producto Usando scripts

(base) binildass-MBP:02-ProductWeb binil$


pwd/Usuarios/binil/binil/code/mac/mybooks/docker-
03/ch02-03/02-ProductWeb(base) binildass-MBP:02-
ProductWeb binil$ sh [Link][INFO] Escaneando
proyectos... [INFO]... 2023-12-20 10:36:29 INFO
[Link] - Start2023-12-20 10:36:29 DEBUG
[Link] - Do Nothing2023-12-20 10:36:29
INFO [Link] - End2023-12-20 10:36:29 INFO
[Link] - Iniciado EcomProd...

Ahora que los microservicios están operativos, puedes probar los


microservicios.

Pruebas del Microservicio


Una vez que ambos microservicios estén operativos, puedes acceder a la
aplicación web usando tu navegador y apuntando a esta URL:
[Link]

Para probar las operaciones CRUD, siga las instrucciones descritas en la


subsección "Probar los microservicios usando la interfaz de usuario" en la
última sección del Capítulo 1, titulado "Su primer microservicio en Java."
Recuerda que activaste el navegador HAL, por lo que Spring configurará
automáticamente el navegador y lo hará disponible desde el punto final
predeterminado (véase la Figura 2-3). Puedes acceder al navegador HAL en:
[Link]

77
Capítulo 2 Más MiCroservices prácticos

Figuras 2-3. El navegador HAL

Ahora puedes probar las distintas opciones con el navegador HAL.

Resumen
En el capítulo 1, viste ejemplos de la arquitectura hexagonal. Este capítulo continuó
esa discusión, con ejemplos de microservicios más complejos. También viste más
ejemplos de puertos y adaptadores. A estas alturas, deberías ser capaz de relacionar
estos conceptos con las muchas interfaces que usas para exponer servicios en el
edge, así como con muchas otras interfaces que usas para invocar otros servicios
desde el edge (de microservicios). Esta idea de puertos y adaptadores que
proporciona la arquitectura hexagonal es una excelente forma de pensar

78
Capítulo 2 Más MiCroservices prácticos

también la forma débil de interactuar entre microservicios. Has visto cómo un


cliente de Feign ofrece eso de forma inteligente con muy poco código específico
de la aplicación. Para completar esta discusión sobre flexibilidad y acoplamiento
débil, el capítulo también abordó HATEOAS. El siguiente capítulo pasa a
aspectos más interesantes en arquitecturas basadas en componentes

79
CAPÍTULO 3

Cebolla y Arquitectura
Hexagonal en la
práctica
El capítulo 1 introdujo la arquitectura hexagonal. También viste algunos
ejemplos en los capítulos 1 y 3 que explicaban cómo los conceptos de
abstractports se realizan mediante contenedores ligeros como Spring y Spring
Boot para ofrecer adaptadores bajo demanda en tiempo de ejecución. Este
capítulo amplía esos conceptos introduciendo la arquitectura Onion, con
ejemplos más precisos y concretos.
Este capítulo cubre los siguientes conceptos:

• Extiende la noción de arquitectura hexagonal en


microservicios usando Spring Boot y PostgreSQL.

• Demuestra arquitectura hexagonal en acción,


conectando MongoDB en lugar de PostgreSQL.

• Introduce el concepto de la arquitectura Onion.

• Introduce GraphQL como un medio tecnológico


para demostrar la arquitectura Onion.

• Demuestra por ejemplo la naturaleza complementaria de


las arquitecturas Hexagonal y Onion.

© Binildas A. Christudas 2024B. A. Christudas, Microservicios 81


Java y contenedores en la nube, [Link]
8688-0555-4_3
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Microservicios usando
PostgreSQLand RestTemplate
En esta sección, ajustarás el primer ejemplo de microservicios que viste en el
Capítulo 2, pero para conectarlos a una base de datos PostgreSQL en lugar
de MongoDB. Tendrás los mismos dos microservicios —un microservicio de
consumidor y otro de proveedor— comunicándose entre sí usando el
protocolo REST. El microservicio proveedor también interactúa con un
PostgreSQL, en lugar de con MongoDB. Consulte la Figura 2-1 del Capítulo
2 para el diseño general.

Diseña el Microservicio
Reutilizarás la vista de microservicios hexagonal que se muestra en la Figura 2-1
del Capítulo 2. Existen algunas diferencias con este diseño, como las siguientes:

• El microservicio Product Server se conecta a una


base de datos PostgreSQL.

• Usarás Liquibase para inicializar la base de datos


PostgreSQL.

• La entidad Product es menos extensa debido al uso de la


biblioteca de Lombok.

• Usarás modelos de entidad separados: el ProductOR


para las interacciones con el Repositorio y el Product
para la interfaz theREST.

• Usarás la biblioteca mapstruct para transformar entidades


entre las estructuras ProductOR y Product Structure.

82
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Entendiendo el Código
El código fuente de este libro está disponible en GitHub a través de la página
de producto del libro, ubicada en [Link]/9798868805547. El código
fuente de este ejemplo está organizado dentro de la carpeta ch03\ch03-01.
Primero mirarás el microservicio del proveedor —es decir, el microservicio
Product Server. El listado 3-1 muestra el repositorio modificado usado para
interactuar con el PostgreSQL.

Listado 3-1. El puerto abstracto para Product Server Microservice


para interactuar con PostgreSQL (ch03\ch03-02\01-
ProductServer\src\main\java\com\acme\ecom\product\repository\
[Link])

@RepositoryRestResource(collectionResourceRel = "productdata",
path = "productdata")interfaz pública
ProductRepository se extiende
CrudRepository<ProductOR, Long> {public
List<ProductOR> findByCode(@Param("code")
Código de cadena);}

Este puerto (interfaz) proporciona operaciones CRUD genéricas en un


repositorio, en este caso un PostgreSQL. Ten en cuenta que
MongoRepository interactúa con MongoDB en todos los ejemplos del
Capítulo 2. Sin embargo, este ejemplo opta por un tipo más genérico de
MongoRepository en la forma de CrudRepository . Hay una razón para hacer
esto. Quiero demostrar cómo un puerto genérico (el puerto conducido con
CrudRepository) puede adaptarse para conectarse a diferentes tipos de bases
de datos—más concretamente a una base de datos PostgreSQL en este
ejemplo y a una base de datos MongoDB en el siguiente ejemplo.

83
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

CrudRepository es una interfaz de Spring Data para operaciones CRUD


genéricas en un repositorio de un tipo específico. Proporciona varios métodos
listos para interactuar con una base de datos. El adaptador específico para
este puerto, un adaptador a una base de datos PostgreSQL, es proporcionado
por Spring en función de la configuración de [Link] (véase Listado 3-2).

Listado 3-2. La pista del adaptador para el microservicio Product Server


(ch03\ch03-02\01-ProductServer\ [Link])

<dependencies>

<groupId>[Link]</groupId>
<artifactId>PostgreSQL</artifactId>
<version>42.2.19</version>
<scope>Duración</scope></dependency>
</dependencies>

En la lista 3-3 se muestra el puerto HTTP compatible con REST,


usando un SpringRestController.

Listado 3-3. Puerto HTTP basado en REST para getAllProducts ProductServer (ch03\ch03-02\01-
ProductServer\src\main\java\com\acme\ecom\product\controller\[Link])

@RestControllerpublic class
ProductRestController {

@Autowiredprivate ProductRepository
repositorio de productos;
@Autowiredprivate mapeador
ProductMapper;

84
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

@ApiOperation(value="Ver una lista de todos los productos",


respuesta = [Link],responseContainer
= "Lista")@RequestMapping(valor =
"/productos",
método = [Link],produces =
{MediaType.APPLICATION_JSON_VALUE})Public
ResponseEntity<List<Product>> getAllProducts() {

<ProductOR> Iterable iterable =


[Link](); <Product>
Lista de listas = nueva ArrayList<Product>
(); for(ProductOR productOR:iterable){
[Link]([Link](productOR));
}if([Link]() == 0){

volver nuevo ResponseEntity<List<Product>>(


HttpStatus.NOT_FOUND);
}return new ResponseEntity<List<Product>>
(list,
[Link]);
}}

El controlador REST tiene métodos CRUD que sincronizan el estado de la


entidad Product con los de la base de datos PostgreSQL. ThegetAllProducts es
un método Java que devuelve una lista de todos los productos en la base de datos
PostgreSQL, definida mediante un protocolo abstracto y formato de entrega
declarados en el puerto REST basado en HTTP. A continuación, se inyecta (o se
utiliza para interceptar) una implementación concreta de este puerto bySpring y
se utiliza en el controlador en tiempo de ejecución. Traducen la carga útil de
datos de peticiones formateadas en JSON desde el canal de entrega HTTP a una

85
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Llamada al método getAllProducts en el núcleo de aplicación. Para recuperar


las entidades realproduct (realproduct entity), los delegados getAllProducts
llaman al puerto controlado, ProductRepository.
Hay dos nuevas bibliotecas de utilidad que necesito comentar aquí. El
primero es ProductMapper, que aparece en los Listados 3-4.

Listado 3-4. Product Entity Mapper (ch03\ch03-02\01-


ProductServer\src\main\java\com\acme\ecom\product\contro
ller\[Link])

@Mapper(componentModel =
"spring")interfaz pública ProductMapper {

entidad productoToApi (entidad


ProductoOR); ProductOR
apiToEntity(Product API);}

Esta API contiene funciones que automáticamente se asignan entre dos


JavaBeans, el ProductOR y el Product en este caso. Con MapStruct, solo
necesitas crear la interfaz, y la biblioteca creará automáticamente una
implementación concreta durante la compilación según la declaración
[Link]. Véase los listados 3-5.

Listados 3-5. Configuración del Mapper en


ProductRestController(ch03\ch03-02\01-ProductServer\[Link])

<dependencies>

<groupId>[Link]</groupId>
<artifactId>mapstruct</artifactId>
<version>[Link]</version>
</dependency></dependencies>

86
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Cuando activas el procesamiento de MapStruct ejecutando una


instalación limpia de mvn, se generará la clase de
implementación bajo /target/generated- sources/annotations/.
El resto de la implementación del controlador REST en el microservicio
Product Server es muy similar a la Lista 1-4 en el Capítulo 1 (con la única
excepción de que, en lugar de la base de datos en memoria, el puerto
ProductRepository se usa para interactuar con un repositorio PostgreSQL), así
que no repito el código completo aquí.
Ahora veamos las clases de Entidad. La clase de entidad Producto, que
está expuesta en la API del microservicio Product Server, se muestra en
Listing 3-6.

Listados 3-6. La Entidad Producto (ch03\ch03-02\01-


ProductServer\src\main\java\com\acme\ecom\product\model\[Link])

@Builder@Data@NoArg
sConstructor@AllArg
sConstructorpublic
clase Product{

@ApiModelProperty(posición =
1)producto privado de
cadena;@ApiModelProperty(posici
ón = 2)nombre de cadena
privado;@ApiModelProperty(posic
ión = 3)código de cadena
privado;;
@ApiModelProperty(posición =
4)privado Título de
cadena;@ApiModelProperty(posici
ón = 5)privado Precio doble;}
87
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

El @Builder del Proyecto Lombok es un mecanismo útil para usar el


Builderpattern sin necesidad de escribir código estándar. Puedes aplicar esta
anotación a una clase o a un método.
@Data es una anotación rápida conveniente que agrupa las características de
@ToString, @EqualsAndHashCode, @Getter/@Setter
and@RequiredArgsConstructor. Es decir, @Data genera todo el boilerplate
que normalmente se asocia con Plain Old Java Objects (POJO) y beans,
principalmente los getters para todos los campos, setters para todos los campos
no finales, y las implementaciones apropiadas toString, equals y hashCode que
involucran los campos de la clase, un constructor que inicializa todos los
campos finales y todos los campos no finales sin inicializador que hayan sido
marcados with@NonNull, para asegurar que el campo nunca sea nulo.
Los listados 3-7 muestran la clase de entidad ProductOR utilizada por
elRepositorio de Producto del microservicio Product Server para mantener
los datos en la base de datos PostgreSQL.

Listado 3-7. La Entidad ProductOR (ch03\ch03-02\01-


ProductServer\src\main\java\com\acme\ecom\product\model\Product
[Link])

import
[Link];@Dat
a@NoArgsConstructor@Entit
y@Table(name
="product")clase pública
ProductOR{

@GeneratedValue(strategy =
[Link])@Id@Column(name =
"productid")privado Long productId;

88
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

@কলাম(name="pronombre")nom
bre de cadena
privada;@কলাম(name="code")
código de cadena privado;;
@কলাম(name="título")Cadena
privada
título;@কলাম(name="price")
Precio privado doble;}

Usas JPA para la persistencia. Las entidades en JPA no son más que
POJOsannotadas con @Entity que representan datos que pueden persistir en la
base de datos. Una entidad representa una tabla almacenada en una base de datos.
Cada instancia de una entidad representa una fila en la tabla. Debes especificar
@Entityannotation a nivel de clase. También debes asegurarte de que la entidad
tenga un constructor ano-arg y una clave primaria. El nombre de la entidad se
asigna por defecto al nombre de la clase. Puedes cambiar su nombre usando el
nombre element@Entity(nombre="producto"). En algunos casos, el nombre de la
tabla en thedatabase y el nombre de la entidad no serán el mismo. En estos casos,
puedes especificar el nombre de la tabla usando la anotación @Table.
Cada entidad JPA debe tener una clave primaria que la identifique de forma única.
The@Id anotación define la clave primaria. Puedes generar los identificadores de
varias maneras, especificadas por la anotación @GeneratedValue. Puedes elegir
entre cuatro estrategias de generación de ID con el elemento estratégico. El valor
puede ser AUTO, TABLE, SEQUENCE o IDENTIDAD.
También puedes usar la anotación @Column para mencionar los detalles
de una columna en la tabla. La anotación @Column tiene muchos
elementos, incluyendo nombre, longitud, anulable y único.
Hay otra razón para introducir la entidad ProductOR. Quiero demostrar
que, al usar la arquitectura de puertos y adaptadores, se pueden reutilizar al
máximo las entidades centrales y los servicios empresariales centrales.

89
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

En otras palabras, quiero demostrar que la entidad Product usada en este


ejemplo se reutiliza también en el siguiente ejemplo, lo que afirmará la
capacidad de conectar diferentes adaptadores controlados en tiempo de
ejecución, reutilizando aún el núcleo. Para ello, la entidad ProductOR se
encargará de todos los detalles específicos del adaptador (base de datos).
La dependencia JPA se menciona en la configuración de Maven.
VéaseListado 3-8.

Listados 3-8. La dependencia JPA en Maven (ch03\ch03-02\01-


ProductServer\ [Link])

<dependencies>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-data-
jpa</artifactId></dependency></dependencies>

El archivo [Link] también revela la dependencia de Liquibase. El


componente central al usar Liquibase es el archivo changeLog, que es un
archivo XML que lleva el control de todos los cambios que deben ejecutarse
para actualizar la base de datos. VéaseListado 3-9.

Listados 3-9. El registro de cambios de Liquibase (ch03\ch03-02\01-


ProductServer\src\main\resources\db\changelog\[Link]-
[Link])

<changeSet id="1" author="Binildas">


<sqlFile path="01_init_product.sql"
relativeToChangelogFile="tr
ue"splitStatements="true"

90
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

stripComments="true"/><comment>Crea tabla con


información del producto</comment></changeSet>
</databaseChangeLog>

Aquí, llama al archivo 01_init_product.sql, que incluye el script, para crear


una tabla de producto si no existe.
En el listado 3-10 se muestra la clase de Microservicio principal
del Product Server.

Listados 3-10. Aplicación principal de microservicio del Product Server


(ch03\ch03-01\01-ProductServer\src\main\java\com\acme\ecom\product\
[Link])

@SpringBootApplication@EnableJpaRepositories("[Link]
[Link]")clase pública
EcomProductMicroserviceApplication {

empty estático público main(String[] args) {

[Link](
[Link], args);
}}

Para activar el soporte para repositorios Spring JPA, este ejemplo utiliza
the@EnableJpaRepositories anotación y especifica el paquete que contiene
las interfaces del DAO.
En el listado 3-11 se muestra el archivo de configuración de Microservicios del
Product Server.

91
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Listados 3-11. El registro de cambios de Liquibase (ch03\ch03-


02\01-ProductServer\src\main\resources\[Link])

[Link] = product-
[Link]=[Link]=jdbc:p
ostgresql://${DB_SERVER}/${POSTGRES_DB}[Link]
[Link]=${POSTGRES_USER}[Link].
password=${POSTGRES_PASSWORD}[Link]
ge-log=classpath:/db/changelog/[Link]-
[Link]
.non_contextual_creation=[Link]-
sql=true

Este archivo espera los parámetros de configuración de la base de datos


PostgreSQL a través del contexto de entorno del microservicio Product Server.
El código de microservicios de Product Web es muy similar al código de
microservicios de Product Web que viste en el Capítulo 2. No repito el código
aquí; en su lugar, se recomienda consultar los Listados 2-6 a 2-8 en el Capítulo 2.

Construye y ejecuta el microservicio


La carpeta ch03\ch03-01 contiene los scripts de Maven necesarios para construir
los ejemplos. Como primer paso, necesitas abrir el servidor PostgreSQL.
Consulta el Apéndice C para aprender a configurar el servidor PostgreSQL y
abrirlo. Tienes que ejecutar los comandos en la lista 3-12 para abrir PostgreSQL.

Listados 3-12. Activando PostgreSQL Server

binildass-MacBook-Pro:~ binil$pg_ctl -D
/Library/PostgreSQL/12/data start

92
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

A continuación, toma dos terminales de comandos y cambia el directorio a


la carpeta de nivel superior de ambos microservicios. Luego construye y
ejecuta el microservicio ProductServer usando los scripts [Link] y
[Link], como se muestra en Listing 3-13.

Listado 3-13. Compilar y ejecutar microservicio del servidor


de producto usando scripts

binildass-MacBook-Pro:01-ProductServer binil$
pwd/Users/binil/binil/code/mac/mybooks/docker-
04/Code/ch03/ch03-01/01-ProductServerbinildass-
MacBook-Pro:01-ProductServer binil$binildass-MacBook-
Pro:01-ProductServer binil$ sh [Link][INFO]
Escaneando proyectos... [INFO][INFO] -<
[Link]:Ecom-Product-Server-Micro >-...
[INFO] -----------------------------------------------
------[INFO] ÉXITO DE BUILD[INFO] --------------------
---------------------------------[INFO] Tiempo
total:3.026 s[INFO] Finalizado en: 2024-01-
03T12:36:02+05:30[INFO] ------------------------------
-----------------------binildass-MacBook-Pro:01-
ProductServer binil$binildass-MacBook-Pro:01-
ProductServer binil$ sh [Link]

. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \(
( )\___ | '_ | '_| | '_ \/ _` | \ \ \
\\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / /
/=========|_|==============|___/=/_/_
/_/:: Bota de Muelle ::(v3.2.0)

93
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

03-01-2024 12:37:17 INFO [Link] - Iniciando EcomProdM...


2024-01-03 12:37:20 INFO [Link] - Iniciar...
2024-01-03 12:37:20 DEPURACIÓN [Link] -
Eliminar... Hibernar: selecciona
pco1_0.categoryid,pco1_0.description,pco1_0.imgurl,pco1_0.nam
e,pco1_0.title desde productcategory pco1_0Hibernate:
selecciona
po1_0.productid,po1_0.category,po1_0.code,po1_0.prodname,po1_
[Link],po1_0.title from product po1_02024-01-03 12:37:20
DEBUG [Link] -Creando datos
iniciales al inicio... Hibernar: insertar en
productocategoría(descripción, imgurl,nombre,título) valores
(?,?,?,?)Hibernar: insertar en productocategoría(descripción,
imgurl,nombre,título) valores (?,?,?,?)Hibernar: insertar en
producto (categoría, código, nombre de nombre, precio,
título) valores (?,?,?,?,?)Hibernar: insertar en producto
(categoría, código, nombre de nombre, precio, título) valores
(?,?,?,?,?)Hibernar: insertar en producto (categoría, código,
nombre de nombre, precio, título) valores
(?,?,?,?,?)Hibernar: insertar en producto (categoría, código,
nombre de nombre, precio, título) valores (?,?,?,?,?)2024-01-
03 12:37:20 [Link] - Fin2024-01-03
12:37:21 [Link] - Inicié EcomProd......

Ten en cuenta que la inicialización se realiza insertando unas filas en la base de datos
PostgreSQL mientras se inicia el microservicio Product Server. A continuación,
construye y ejecuta el microservicio Product Web, como se muestra en la Lista 3-14.

94
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Listado 3-14. Compilar y ejecutar microservicio web de


producto Usando scripts

binildass-MacBook-Pro:02-ProductWeb binil$
pwd/Users/binil/binil/code/mac/mybooks/docker-
04/Code/ch03/ch03-01/02-ProductWebbinildass-MacBook-
Pro:02-ProductWeb binil$ sh [Link][INFO] Escaneando
proyectos... [INFO]... binildass-MacBook-Pro:02-
ProductWeb binil$binildass-MacBook-Pro:02-ProductWeb
binil$ sh [Link]... 03-01-2024 12:43:58 INFO
[Link] - Iniciando EcomProd... 2024-01-03
12:43:59 INFO [Link] - Start2024-01-03
12:43:59 DEBUG [Link] - Nothing
Nothing2024-01-03 12:43:59 INFO [Link]
- End2024-01-03 12:43:59 INFO [Link] -
Iniciado EcomProd...

Ahora que ambos microservicios están operativos, puedes probar los


microservicios.

Pruebas del Microservicio


Una vez que ambos microservicios estén operativos, puedes inspeccionar tu
servidor PostgreSQL usando el terminal psql para asegurarte de que el
microservicio del Product Server insertó algunos productos en el servidor
PostgreSQL durante el proceso de arranque del microservicio. Consulte el
Apéndice C para aprender a usar el terminal thepsql.

95
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Listado 3-15. Inspeccionando el servidor PostgreSQL usando un shell psql

postgres=# conectar productdbAhora estás conectado a la


base de datos "productdb" como usuario
"postgres".productdb=# seleccione * de producto;
productid | Prodnance | Código | Título | Precio
-----------+-------------+---------+---------------+-----
1 | Kamsung D3 | KAMSUNG | Kamsung Tr.. |
120002 | Lokia Pomia | LOGS| Registro 1.| 9009
(2
filas)productdb=#

Cuando todo esté listo, puedes acceder a la aplicación web desde tu


navegador. Apunta a esta URL: [Link]

Para probar las operaciones CRUD, siga las instrucciones descritas en la


subsección "Probar los microservicios usando la interfaz de usuario" en la
última sección del Capítulo 1, titulado "Su primer microservicio en Java."
Una vez que hayas ejecutado los casos de prueba en este ejemplo, puedes
pasar al siguiente, que pretende demostrar una de las muchas grandes
flexibilidades de la arquitectura hexagonal: plug and play.

Microservicios usando
MongoDB y CrudRepository
Este ejemplo modifica el primer ejemplo de microservicios que viste en el
Capítulo 2 para conectarlos a un MongoDB, usando el CrudRepository en
lugar del MongoRepository. Tienes los mismos dos microservicios —un
consumidor y un proveedor microservicio— comunicándose entre sí usando el
protocolo REST. El microservicio del proveedor también interactúa con
aMongoDB. Consulte la Figura 2-1 del Capítulo 2 para el diseño general.

96
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Arquitectura hexagonal revisitada


He reutilizado la vista de microservicios hexagonal que se muestra en la Figura
2-1 del Capítulo 2. Sin embargo, usarás CrudRepository en lugar de
MongoRepository. Quiero demostrar cómo un puerto genérico (el puerto
controlado con CrudRepository en este caso) puede ser "adaptado usando
adaptadores adecuados" para conectarse a diferentes tipos de bases de datos—
más concretamente a una base de datos MongoDB en este ejemplo.
Además, introduje la entidad ProductOR en el último ejemplo. La razón de
esto es que quiero demostrar que, al usar la arquitectura de adaptadores de
puertos y puertos, puedes reutilizar al máximo las entidades centrales y los
servicios empresariales. En otras palabras, quiero demostrar que también
conservarás y reutilizarás una entidad Product del último ejemplo de este
ejemplo, que afirmará la capacidad de conectar diferentes adaptadores
impulsados en tiempo de ejecución.

Entendiendo el Código
El código fuente de este libro está disponible en GitHub a través de la página
de producto del libro, ubicada en [Link]/9798868805547. El código
de este ejemplo está organizado dentro de la carpeta ch03\ch03-02. Primero
mirarás el microservicio del proveedor —es decir, el microservicio Product
Server—. La lista 3-16 comienza con el repositorio modificado que se usa para
interactuar con el PostgreSQL.

Listado 3-16. El puerto abstracto para Product Server Microservice toInteraction with MongoDB
(ch03\ch03-02\01-
ProductServer\src\main\java\com\acme\ecom\product\repository\[Link]

@RepositoryRestResource(collectionResourceRel =
"productdata", path = "productdata") interfaz pública
ProductRepository extends
CrudRepository<ProductOR, String> {

97
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Lista pública<ProductOR> findByCode(@Param("code")


Stringcode); Lista pública<ProductOR>
findPorCategoría(@Param("categoría")

Cuerda categoría);
}

Este ejemplo conserva el CrudRepository para operaciones CRUD genéricas


en un repositorio de un tipo específico. El adaptador específico para este
puerto, un adaptador a una base de datos MongoDB, es proporcionado por
Spring en función de la configuración en [Link]; véase el Listado 3-17.

Listado 3-17. El archivo de Microservicio Maven del Product Server


(ch03\ch03-02\01-ProductServer\[Link])

<dependencies>

<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-data-
mongodb</artifactId></dependency>
<dependency>

<groupId>[Link]</groupId>
<artifactId>[Link]-API</artifactId>
<version>2.2</version></dependency>
</dependencies>

También cambié la dependencia de persistencia solo a su API. El resto de la


implementación del controlador REST en el microservicio ProductServer es
muy similar al código del Listado 1-4 en el Capítulo 1 (con la única
excepción de que, en lugar de la base de datos en memoria, el puerto
ProductRepository se usa para interactuar con un repositorio MongoDB),
por lo que no repito el código completo aquí.

98
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

La clase de entidad Producto es similar al ejemplo anterior, como se muestra


en el Listado 3-6. He mantenido esta clase como entidad API, por lo que
tengo su contraparte ProductOR para gestionar las interacciones con la base
de datos. El código para ProductOR es muy similar al mostrado en el ejemplo
anterior en el Listado 3-7, con diferencias sutiles, que se comentan y se
reemplazan por un nuevo código en el Listado 3-18.

Listado 3-18. La Entidad ProductOR (ch03\ch03-02\01-


ProductServer\src\main\java\com\acme\ecom\product\model\Product
[Link])

import [Link];//import
[Link];

@ডাটা@নোর্গস্কনস্টর@এনটিটি@টেবল(name="producto")Pu
blic Class Product{@জেনারেটেডভালু(Strategy =
[Link])@আইডি@কলাম(name="Pro
duct")//Private Long Productide; Producto de
cadena
privada;@কলাম(nombre="pronombre")Nombre de
cadena privada;@কলাম(nombre="código")Código
de cadena privado;; @কলাম(name="title")Título
privado de cadena;

99
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

@Column(name =
"price")privado Doble
precio;@Column(name =
"categoría")privado Cadena
categoría;}

Si pides a MongoDB que genere automáticamente un ID para el tipo Long,


se quejará, así que cambié el ID a String. Después, cambié el @Idannotation
de [Link] a springframework para que el valor ID quede expuesto
a través de los métodos de la API. ProductoOR protege así la diferencia de
impedancia entre bases de datos de la clase de entidad Producto. Esto hace
que la entidad Producto sea reutilizable.
El resto de las clases en el microservicio Product Server son similares a lo
que viste en el ejemplo anterior. El código del microservicio Web del
Producto tampoco ha cambiado respecto al ejemplo anterior, por lo que no
se repite aquí.

Construye y ejecuta el microservicio


La carpeta ch03\ch03-02 contiene los scripts Maven necesarios para
construir los ejemplos. Como primer paso, necesitas abrir el servidor de
MongoDB. Consulta el Apéndice B para aprender cómo configurar un
servidor MongoDB y abrirlo. Necesitas ejecutar los comandos de la lista 3-
19 para abrir MongoDB.

Listado 3-19. Abriendo el servidor MongoDB

(Base) binildas-MBP:Bin
Vinil$pued/Users/Vinil/APLNS/Mangadab/Mangadab-macOS-x86_64-
4.2.8/Bin(Base) Binildas-MBP:Bin Vinil$Mangad --
dbpith/usr/local/var/mangdab --
logpath/usr/local/var/log/mangadab/[Link]

100
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

A continuación, toma dos terminales de comandos y cambia el directorio a


la carpeta de nivel superior de ambos microservicios. Luego, compila y
ejecuta el microservicio ProductServer usando los scripts [Link] y
[Link], como se muestra en Listing 3-20.

Listado 3-20. Compilar y ejecutar microservicio del servidor


de producto usando scripts

binildass-MacBook-Pro:01-ProductServer binil$
pwd/Users/binil/binil/code/mac/mybooks/docker-
04/Code/ch03/ch03-02/01-ProductServerbinildass-MacBook-
Pro:01-ProductServer binil$ sh [Link][INFO] Escaneando
proyectos... [INFO]... binildass-MacBook-Pro:01-
ProductServer binildass$binildass-MacBook-Pro:01-
ProductServer binil$ sh [Link]... 03-01-2024 13:13:59
INFO [Link] - Iniciando EcomProd... 2024-01-03
13:14:01 INFO [Link] - Inicio... 2024-
01-03 13:14:01 DEPURACIÓN [Link] -
Borrar ... 2024-01-03 13:14:01 DEBUG
[Link] - Create init2024-01-03 13:14:01
INFO [Link] - End2024-01-03 13:14:01
INFO [Link] - Iniciado EcomProd...

A continuación, construye y ejecuta el microservicio Product Web,


como se muestra en Listing 3-21.

101
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Listado 3-21. Compilar y ejecutar microservicio web de


producto Usando scripts

binildass-MacBook-Pro:02-ProductWeb binil$
pwd/Users/binil/binil/code/mac/mybooks/docker-
04/Code/ch03/ch03-02/02-ProductWebbinildass-MacBook-
Pro:02-ProductWeb binil$ sh [Link][INFO] Escaneando
proyectos... [INFO]... binildass-MacBook-Pro:02-
ProductWeb binil$binildass-MacBook-Pro:01-
ProductServer binil$ sh [Link]... 03-01-2024 13:17:09
[Link] - Iniciando EcomProd... 2024-01-03
13:17:10 [Link] - Start2024-01-03
13:17:10 DEBUG [Link] - Do Nothing2024-
01-03 13:17:10 [Link] - End2024-01-
03 13:17:10 [Link] - Iniciado
EcomProd......

Ahora que ambos microservicios están operativos, puedes probar los


microservicios.

Pruebas de los microservicios


Una vez que ambos microservicios estén operativos, puedes inspeccionar
tu servidor MongoDB usando la terminal Mongo para asegurarte de que
el microservicio ProductServer insertó algunos productos en el servidor
MongoDB durante el arranque del microservicio. Véase el Listado 3-22.

102
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Listado 3-22. Inspeccionar el servidor MongoDB usando un shell Mongo

> [Link](){ "_id" :


ObjectId("61a5e3bc80e0e72c72097305"), "name": "Kamsung
Mobile", "code": "KAMSUNG-TRIOS", "title" :"Tablet Trios 12
pulgadas, negro, 12 px ....", "precio" : 12000, "categoría" :
"Móvil", "_class" : "[Link]" }
{ "_id" : ObjectId("61a5e3bc80e0e72c72097306"), "name" :
"LokiaMobile", "code" : "LOKIA-POMIA", "title" : "Lokia 12
pulgadas, blanco, 14px ....", "precio" : 9000, "categoría" :
"Mobile", "_class" : "[Link]"
}{ "_id" : ObjectId("61a5e3bc80e0e72c72097307"), "name"
:"Mapple Mobile", "code" : "MAPPLE-EPHONE", "title" :
"Mapple7 inch, morado, 14px ....", "precio" : 8000,
"category" : "Mobile", "_class" :
"[Link]" }{ "_id" :
ObjectId("61a5e3bc80e0e72c72097308"), "name" :"Mapple
Tablet", "code" : "MAPPLE-PAD", "title" : "Mapple11 pulgadas,
gris, 140px ....", "precio" : 19000, "categoría" :"Tablet",
"_class" : "[Link]" }>

Cuando todo esté listo, puedes acceder a la aplicación web desde tu


navegador. Apunta a esta URL: [Link]

Para probar las operaciones CRUD, siga las instrucciones descritas en la


subsección "Probar los microservicios usando la interfaz de usuario" en la
última sección del Capítulo 1, titulado "Su primer microservicio en Java."
Ahora es momento de consolidar tu aprendizaje hasta ahora e introducir el
siguiente concepto, la arquitectura Onion.

103
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

La arquitectura de la cebolla
El principio de capas permite a los arquitectos de software separar las
preocupaciones. Los arquitectos de software llevan décadas construyendo con
éxito arquitecturas de software en capas, y hoy en día estos principios en capas han
ganado terreno con la adopción generalizada de la arquitectura de microservicios.
Veamos qué tiene que ver la superposición de capas con las cebollas.

Diseño de la Arquitectura Onion


En la arquitectura de puertos y adaptadores explicada en los capítulos
anteriores, aprendiste a definir puertos y adaptadores abstractos que protegen
los servicios y entidades del negocio principal del contexto y la intención del
software. En otras palabras, estos puertos y adaptadores aíslan el núcleo de
software de la infraestructura y de los periféricos al escribir adaptercode para
que la infraestructura y el código periférico no se filtren al núcleo de la
aplicación. La arquitectura Onion representa aplicaciones empresariales con
múltiples capas, y algunas de estas capas en la lógica de negocio pueden ser
reconocibles respecto a los principios del diseño dirigido por dominios. Una
arquitectura típica de Onion se representa en la Figura 3-1.

104
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Figura 3-1. Arquitectura cebolla

En referencia a la Figura 3-1, los dos principios fundamentales


en la arquitectura de software son:

• Las capas externas dependen de las capas internas

• Las capas exteriores son transparentes respecto a las capas internas. Al ver la
Figura 3-1, la dirección de acoplamiento de capas es hacia el centro,
proporcionando un modelo de objeto independiente (modelo de dominio), que
en su núcleo no depende de nada. Esta capa interna contiene los datos y la
lógica para manipular datos específicos del dominio de la propia aplicación.

105
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Muchas veces, también te encontrarás con lógica que involucra múltiples entidades, y
dicha lógica de dominio puede no pertenecer a una entidad específica. Dicha lógica
también podría reutilizarse, de modo que requiere otra capa, llamada capa de Servicios
de Negocio. Estos servicios empresariales —también conocidos como servicios de
dominio— tienen la función de recibir un conjunto de entidades y realizar cierta lógica
de negocio sobre ellas. Estos servicios de dominio podrían agregar también más
servicios de dominio y entidades empresariales (véase la Figura 1-14 en el Capítulo 1).

Cebolla vs. Arquitectura Hexagonal


Los puertos y adaptadores definidos en la arquitectura hexagonal sirven para
aislar el núcleo de la aplicación de software de la infraestructura y de las
preocupaciones periféricas. Estos periféricos pueden ser una interfaz de
usuario, sea cual sea el tipo de interfaz, como un navegador, un dispositivo
móvil, un escáner, etc. De manera similar, el código de infraestructura podría
conectar el application core a herramientas como una base de datos, un sistema
de terceros, una impresora, etc. La capa de infraestructura, que se convierte en
el anillo de cebolla más externo, lo muestra en la arquitectura de la cebolla en
la Figura 3-1. También puedes visualizarlos colocados en el límite del
hexágono, como puertos abstractos y adaptadores.
Estos puertos y adaptadores están conectados a las capas internas a través de lo que
llamamos servicios de aplicación. Estos son servicios técnicos que manejan
transformaciones y optimizaciones de protocolo y formato. Por ejemplo, un controlador
aREST es un servicio de aplicación que expone entidades como JSON a través de un
transporte HTTP. De manera similar, las abstracciones de persistencia a un tipo específico
de base de datos podrían hacerse usando una interfaz de repositorio, como viste en los dos
primeros ejemplos de este capítulo, que de nuevo son tipos de servicios de aplicación. Por
tanto, esta segunda capa de la cebolla son las capas internas reutilizables.
Tras debatir suficiente teoría, veamos algunos ejemplos prácticos. Si vuelves a
los dos ejemplos anteriores de este capítulo, puedes visualizar cómo las entidades
de dominio (Producto) se reutilizan a través de diferentes abstracciones de
persistencia en una base de datos PostgreSQL y una de MongoDB,

106
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

que son interfaces controladas. Ahora ampliaré el mismo ejemplo para


demostrar cómo se pueden definir puertos para permitir múltiples
abstracciones de controladores. Para ser más específicos, has visto cómo una
interfaz REST para los microservicios proporciona abstracciones finas como
puertos de controladores. Conectaré otro puerto, uno que use tecnología
GraphQL, a los mismos microservicios en el anillo más externo de la cebolla
para que los anillos interiores de la misma cebolla puedan reutilizarse.

GraphQL
GraphQL es un lenguaje de consulta y manipulación de datos de código abierto para
APIs, y un tiempo de ejecución para cumplir consultas con datos existentes.
GraphQL fue desarrollado internamente por Facebook en 2012. El proyecto GraphQL
se trasladó posteriormente de Facebook a la recién creada GraphQL Foundation,
alojada por la organización sin ánimo de lucro Linux Foundation. Voy a repasar
rápidamente GraphQL para que puedas apreciar el siguiente ejemplo de este capítulo.

Explicación de GraphQL
GraphQL permite a los clientes pedir exactamente lo que necesitan y nada
más, facilitando así la evolución de las APIs con el tiempo. Permite a los
clientes definir la estructura de los datos requeridos, y la misma estructura de
los datos se devuelve desde el servidor, evitando así que se devuelvan
cantidades excesivamente grandes de datos. Es muy deseable en dispositivos
de perfil bajo como móviles, IOT, etc. Permite al cliente navegar a recursos
hijos en una sola petición, y así permite múltiples consultas en una sola
petición.
GraphQL utiliza la noción de consultas y mutaciones nombradas en lugar
de un conjunto obligatorio estándar de acciones. Esto ayuda a poner el
control donde corresponde, con el desarrollador de la API especificando lo
que es posible y con el consumidor de la API lo que se desea. En las listas
3-23 aparecen una consulta de ejemplo.

107
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Listado 3-23. Una consulta de GraphQL

consulta {
productos(conteo: 10, desplazamiento: 0) {
productIdcodepr
oductCategory {

idnametitle}}}

Esta consulta de GraphQL está destinada a hacer lo siguiente:


• Solicita los diez productos añadidos más recientemente
• Para cada producto, solicita el productId y el código
•Para cada solicitud de producto, su Categoría de producto, devolviendo el id,
nombre y título de la categoría de producto correspondiente. En una API
REST tradicional, esto requiere 11 solicitudes—una para la consulta inicial de
productos y diez para su correspondiente Categoría de producto—o debe
incluir los detalles de la Categoría de producto junto con los postdetalles,
haciendo que la carga útil sea grande.

Ejemplo de microservicio de la Arquitectura Onion


Este ejemplo modifica el anterior ejemplo de los microservicios. Utiliza los
mismos dos microservicios —un microservicio de consumidor y otro de
proveedor— que se comunican entre sí mediante el protocolo REST. El
proveedor microservicio también interactúa con un MongoDB. El microservicio
para consumidores expone un puerto adicional basado en GraphQL.

108
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Diseño de cebolla para el microservicio


Si superpones la vista hexagonal de microservicios mostrada en la Figura 2-
1 del Capítulo 2 sobre la vista de la arquitectura Onion en la Figura 3-1 de
este capítulo, obtienes la Figura 3-2.

Figura 3-2. Arquitectura onion para microservicios de


consumidores y proveedores

En ambos microservicios mostrados en la Figura 3-2, se utilizan puertos HTTP en


las interfaces REST, que especifican cómo el navegador del usuario u otro cliente
HTTP puede usar el núcleo de la aplicación. Para el microservicio Product Web,
especificas un puerto adicional basado en GraphQL. También puedes definir un
servicio empresarial destinado a demostrar que las instancias de servicio
empresarial de las capas internas son reutilizadas por las capas externas de la
Onionarchitecture, igual que reutilizan las clases de entidad empresarial.

109
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Organización del código


El código fuente de este libro está disponible en GitHub a través de la página
de producto del libro, ubicada en [Link]/9798868805547. El código
de este ejemplo está organizado como se muestra en la lista 3-24, dentro de la
carpeta ch03\ch03-03. Esto sigue la estructura estándar de Maven, por lo que
[Link] está en la raíz del directorio. Se muestra la organización del código
solo para la parte relevante del microservicio de ProductWeb, ya que el
microservicio Product Server es similar a lo que ya has visto.

Listado 3-24. Organización del código fuente de Spring Boot

./ch03-03/├── 01-ProductServer│├── ... │.├── 02-


ProductWeb│├── [Link]│└── src│└── main│├── java││└──
com││── acme││└── ecom││└── product│││─ product �──
[Link]││├── [Link]││├──
Configuración│││└─ [Link]││├──
Controlador││├─ [Link]│││├─
[Link]│││└─ [Link]

110
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

││├── GraphQL│││├── [Link]│││├──


[Link]│││└─ [Link]││├──
Modelo│││├── [Link]│││└─ [Link]││└──
Service││└── [Link]│└── Resources│├──
[Link]│├── GraphQL││└── Schema.│── Esquema.│├──
││├── GraphQL││└── Esquema.» graphqls│├── log4j2-
[Link]│└── estática│├── ... │.└── [Link]

He añadido las siguientes carpetas y archivos nuevos, que se explican a


continuación: ch03\ch03-03\02-
ProductWeb\src\main\java\com\acme\ecom\product\graphqlch03\ch03-
03\02-
ProductWeb\src\main\java\com\acme\ecom\product\servicech03\ch03-
03\02-ProductWeb\src\main\resources\graphql\[Link]

Entendiendo el Código
Esta sección analiza primero los cambios en el microservicio del proveedor —
es decir, el microservicio Product Server.

111
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Gran parte de la implementación del controlador REST en el microservicio


Product Server es similar al código del Listado 1-4 en el Capítulo 1 (con la
excepción de que, en lugar de la base de datos en memoria, se utilizan los
puertos ProductRepository y ProductCategoryRepository para interactuar con
el repositorio aMongoDB), por lo que no repito el código completo aquí. Sin
embargo, introduje dos métodos nuevos para ProductRestController, como se
muestra en Listing 3-25.

Listado 3-25. Puerto HTTP basado en REST para Product Category


BasedQueries en Product Server (ch03\ch03-03\01-
ProductServer\src\main\java\com\acme\ecom\product\controller\Pro
[Link])

@RestControllerpublic class
ProductRestController {

@Autowiredprivate
RepositorioProductoRepositorioProducto;
@Autowiredprivate
RepositorioCategoríaProducto
repositorioCategoríaProduct
o;@RequestMapping(valor =
"/productsbycat/{productcategoryname}",method
= [Link],produces =
{MediaType.APPLICATION_JSON_VALUE})Public
ResponseEntity<List<Product>>
cadena getProductsByCategory(@PathVariable("nombredeproductocategoría")
Cadena

NombreDeCategoríaDeproducto)
{Lista<ProductOR> productoresORs =
[Link](
productoNombreCategoría);

112
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

if([Link]()){
volver nueva ResponseEntity<
Lista<Product>>(HttpStatus.NOT_FOUND);
}<Product>Lista lista = nueva
ArrayList<Product> (); for(ProductOR
productOR:productORs)
{[Link]([Link](productOR)
);}volver nueva ResponseEntity<

List<Product>>(lista, [Link]);
}@RequestMapping(val
or =
"/category/{category}", método = [Link],produces
= MediaType.APPLICATION_JSON_VALUE)entidad de
respuesta<ProductCategory> pública getCategory(
@PathVariable("categoría") Categoría de cadenas)
{<ProductCategoryOR>Listar productoCategoríaOOS =
productoCategorí[Link]
e(categoría); if([Link]()){
return new <ProductCategory>ResponseEntity(
HttpStatus.NOT_FOUND);
}CategoríaDeProductoO
primeroCategoríaProductoOR =
[Link]().next();
return new <ProductCategory>ResponseEntity(
[Link](
firstProductCategoryOR), [Link]);
}}

113
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Estos dos nuevos métodos utilizan sus respectivos repositorios para


recuperar entidades correspondientes, que serán utilizadas por la
implementación de GraphQL, que explicaré pronto.
El listado 3-26 analiza el microservicio para consumidores: el microservicio
Web de Producto. Esto comienza con el puerto HTTP compatible con REST,
usando un SpringRestController.

Listado 3-26. Puerto HTTP basado en REST para getAllProducts ProductWeb (ch03\ch03-
03\02-
ProductWeb\src\main\java\com\acme\ecom\product\controller\[Link])

@CrossOrigin@RestControllerpubl
ic class ProductRestController{

@Autowiredprivate ProductoNegocioServicio
productoNegocioServicio; @RequestMapping(valor =
"/productosweb",
método = [Link],produces =
{MediaType.APPLICATION_JSON_VALUE})Public
ResponseEntity<List<Product>> getAllProducts() {

Lista<Product> productoLista =
[Link]
ctos(); volver nueva ResponseEntity<
List<Product>>(productList, [Link]);
}}

El aspecto notable del microservicio Web de Producto es que delega todas las
llamadas a un Servicio de NegocioProducto. Aquí, el ProductRestController es
una clase de servicio de aplicación, mientras que el ProductBusinessService

114
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

es una clase de servicio empresarial. El resto de los métodos en


theProductRestController no se repiten aquí por brevedad. El listado 3-27
inspecciona la clase de servicio empresarial.

Listado del 3 al 27. El Servicio de Negocio de Producto (ch03\ch03-03\02-


ProductWeb\src\main\java\com\acme\ecom\product\service\ProductBusine
[Link])

@Servicepublic class
ProductBusinessService{

@Value("${acme. PRODUCT_SERVICE_BY_CAT_URL}")privado
String PRODUCT_SERVICE_BY_CAT_URL;@Value("${acme.
PRODUCT_CATEGORY_URL}")Private String
PRODUCT_CATEGORY_URL;@Autowiredprivate RestTemplate
restTemplate; Public List<Product>
getProductsForCategory(String name) {

ReferenciaDeTipo<Lista<Product>>
responseTypeRep = nueva ParameterizedTypeReference<
List<Product>>() {};
EntidadRespuesta<Lista<Product>> entidad =
[Link](
PRODUCT_SERVICE_BY_CAT_URL + "/" +
nombre,[Link], (HttpEntity<Product>)
null,responseTypeRef);
List<Product> productList =
[Link](); return productList;}

115
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

CategoríaProducto pública getCategoríaProducto(


Producto de cadenaNombreCategoría) {String
uri = PRODUCT_CATEGORY_URL + "/" +
productoNombreCategoría;
ProductoCategoríaProductoCategoríaProducto =
[Link](uri,
Categorí[Link]); return
productCategory;}}

@Service anota clases en la capa de servicio, que son casos especiales de


@Component. Puedes marcar los granos con @Service para indicar que están
conteniendo la lógica de negocio. El patrón típico de implementación dentro
del negocio de producto y servicio se muestra en la Lista 3-27. Puedes ver que
las llamadas se dirigen a los métodos respectivos en el microservicio Product
Server.
Ahora has llegado a la implementación de GraphQL. GraphQL debería tener
un esquema que describa la API. Necesitas tener estos archivos de esquema
.graphqls o .gqls en la ubicación src/main/resources/graphql/** para que
Spring Boot pueda recogerlos automáticamente. Véase el Listado 3-28.

Listado del 3 al 28. El esquema Product GraphQL (ch03\ch03-


03\02-ProductWeb\src\main\resources\graphql\[Link])

tipo Product
{productId: ID!
nombre: Cadena!código:
Cadena!título: Cadena!precio:
Flotación!productoCategoría:
ProductoCategoría!}

116
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

tipo ProductoCategoría {
id: ID!name: String!title:
String!description:
String!imgUrl: String!products:
[Product]!}# La consulta raíz
para la consulta de tipo de
aplicación {

productos(conteo: Int, desplazamiento: Int):


[¡Producto]!}# La mutación raíz para el tipo
de aplicación Mutación {

writeProduct(nombre: String!, código: String!, título:


String!, precio: Float!, categoría: String!) :
¡Product!}

Este esquema está compuesto por definiciones de tipos. Cada tipo tiene uno o
más campos, que cada uno toma cero o más argumentos y devuelven un tipo
específico. ¡El ! al final de algunos nombres indica que son tipos no anulables.
El gráfico muestra cómo estos campos están anidados entre sí.
El esquema GraphQL en la Lista 3-28 es para las definiciones de producto,
describiendo un producto, una categoría del producto y una consulta raíz para obtener
los productos añadidos más recientemente. Debe haber exactamente una consulta de
raíz, y hasta una mutación de raíz. La consulta raíz necesita tener frijoles especiales
definidos en el contexto Spring para manejar los distintos campos en esta consulta raíz.
A continuación, tienes que resolver la consulta raíz. Como se ha dicho, necesita
métodos especialmente anotados para manejar los distintos campos. Lo haces
anotando los métodos del manejador con @QueryMapping anotaciones

117
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

y luego colocarlos dentro de componentes de @Controller estándar en la


aplicación. Esto registra las clases anotadas como componentes de obtención
de datos en la aplicación GraphQL, como se muestra en el Listado 3-29.

Listado 3-29. El Resolvedor de Consultas Raíz (/ch03/ch03-03/02-


ProductWeb/src/main/java/com/acme/ecom/product/controller/Product
[Link])

@Controllerpublic class
ProductGraphQLController {

ProductDao privado, productDao; producto


privadoCategoríaDao productoCategoríaDao; public
ProductGraphQLController(ProductDao productDao,

ProductoCategoríaDao productoCategoríaDao)
{[Link] = productDao;
[Link] =
productCategoryDao;}@QueryMappingpublic
Lista<Product> de productos (@Argument conteo
de inteligencia,
@Argument int offset) {return
[Link](count, offset);}}

Como puedes ver, yo defino los productos de método, que usaré para gestionar
cualquier consulta de GraphQL para el campo Products en el esquema definido
antes. El método también debe tener parámetros anotados con @Argument que
correspondan a los parámetros relacionados en el esquema. El método debe

118
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

devolver el tipo de retorno derecho para el tipo en el esquema GraphQL. Puedes


usar cualquier tipo simple como Int, String, List, etc., con los equivalentes tipos
Java, y el runtime de GraphQL simplemente los mapea automáticamente.
Cualquier tipo complejo en el servidor GraphQL está representado por un
Java bean correspondiente. La misma clase Java siempre representará el
mismo tipo GraphQL. Cualquier campo o método en Java bean que no se
asigne al esquema GraphQL será ignorado silenciosamente sin causar
problemas. En este caso, Product y ProductCategory no son triviales de
cargar. Por lo tanto, la anotación @SchemaMapping mapea el método
handlermethod a un campo con el mismo nombre en el esquema y lo utiliza
como theDataFetcher para ese campo, como se muestra en la lista 3-30.

Listados 3-30. El Resolvedor de Consultas Raíz (/ch03/ch03-03/02-


ProductWeb/src/main/java/com/acme/ecom/product/controller/Product
[Link])

@Controllerpublic class
ProductGraphQLController {

@SchemaMappingpublic
ProductoCategoríaProductoCategoría(Producto producto) {

return [Link](
[Link]());
}@SchemaMappingpublic
Lista<Product> de
productos(

ProductCategory productCategory) {return


[Link](
productoCategorí[Link]());
}}

119
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Si el cliente no solicita un campo explícitamente, el servidor GraphQL no hará


el trabajo de recuperarlo. En este caso, si el cliente recupera un producto y no
pide el campo ProductCategory, el método productCategory() no se ejecutará y
la llamada productCategoryDao no se realizará.
En la lista 3-31 se muestra la clase Data Fetcher.

Listado del 3 al 31. Obtendor de datos de producto (/ch03/ch03-03/02-


ProductWeb/src/main/java/com/acme/ecom/product/graphql/ProductD
[Link])

clase pública ProductDao {

@Autowiredprivate ProductoNegocioServicio
ProductoNegocioServicio; public List<Product>
getProducts(int count, int offset) {

Lista<Product> productoLista =
[Link](
); return [Link]().skip(offset).
limit(count).collect([Link]());
}}

Este Data Fetcher delega llamadas al servicio de negocio que ya has visto.
Más adelante verás que las instancias de este servicio producto-negocio se
agrupan o se reutilizan independientemente de por qué puerto llegue la
solicitud del cliente al servidor.
Una vez definido el puerto abstracto basado en GraphQL, Spring BootGraphQL Starter
ofrece una forma elegante de poner en marcha un servidor GraphQL, definiendo las
dependencias respectivas en [Link], como se muestra en el Listado 3-32.

120
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Listado 3-32. La dependencia de Microservicio de la Web Producto


(ch03\ch03-03\02-ProductWeb\[Link])

<dependencies>

<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-
graphql</artifactId></dependency><dependency>

<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency></dependencies>

GraphQL es independiente del transporte. Por eso he incluido el inicio web


en esta configuración. Esto expondrá la API de GraphQL sobre HTTP
usando SpringMVC en el endpoint /graphql por defecto.
GraphQL también tiene una herramienta complementaria de interfaz llamada
GraphiQL. ThisUI puede comunicarse con cualquier servidor compatible con
GraphQL y ejecutar consultas y mutaciones contra él. Véase la Figura 3-3.

121
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Figura 3-3. Navegador de consultas GraphiQL

Por último, necesitas configurar el microservicio Web de Producto, como se


muestra en el Anuncio 3-33.

Listado del 3 al 33. La configuración del microservicio Web del Producto


(ch03\ch03-03\02-ProductWeb\src\main\resources\[Link])

Primavera:
Aplicación:
Nombre: PRODUCT-
WebgraphQL:
Graphiql:
habilitado: verdadero

122
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Servidor:
PUERTO:
8080ACME:
PRODUCT_SERVICE_URL:
[Link]
[Link]
T_URL: [Link]

La mayoría de estas configuraciones aquí son triviales. Lo que necesitas mirar


explícitamente es la herramienta complementaria de GraphQL, GraphiQL. Esta
herramienta de interfaz puede comunicarse con cualquier servidor GraphQL y
ayuda a desarrollar y consumir contra una API GraphQL. Spring GraphQL
viene con una página defaultGraphQL que se expone en el extremo /graphiql.
Este endpoint está deshabilitado por defecto, pero puede activarse activando la
propiedad [Link], que se realiza en el Listado 3-33.
Esto funciona como una forma rápida pero práctica dentro del navegador para
escribir y probar consultas, especialmente durante el desarrollo y las pruebas.

Construye y ejecuta el microservicio


La carpeta ch03\ch03-03 contiene los scripts Maven necesarios para
construir estos ejemplos. Como primer paso, necesitas abrir el servidor de
MongoDB. Consulta el Apéndice B para aprender cómo configurar el
servidor MongoDB y activarlo. Tienes que ejecutar los comandos en la lista
3-34 para abrir MongoDB.

Listado 3-34. Abriendo el servidor MongoDB

(Base) binildas-MBP:Bin
Vinil$pued/Users/Vinil/APLNS/Mangadab/Mangadab-macOS-x86_64-
4.2.8/Bin(Base) Binildas-MBP:Bin Vinil$Mangad --
dbpith/usr/local/var/mangdab --
logpath/usr/local/var/log/mangadab/[Link]

123
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

A continuación, toma dos terminales de comandos y cambia el directorio a


la carpeta de nivel superior de ambos microservicios. Luego, compila y
ejecuta el microservicio ProductServer usando los scripts [Link] y
[Link], como se muestra en Listing 3-35.

Listado 3-35. Compilar y ejecutar microservicio del servidor


de producto usando scripts

(base) binildass-MacBook-Pro:01-ProductServer binil$


pwd/Users/binil/binil/code/mac/mybooks/docker-
04/Code/ch03/ch03-03/01-ProductServer(base) binildass-
MacBook-Pro:01-ProductServer binil$ sh [Link][INFO]
Escaneando proyectos... [INFO]... binildass-MacBook-
Pro:01-ProductServer binildass$binildass-MacBook-Pro:01-
ProductServer binil$ sh [Link]... 2024-01-21 20:44:22
[Link] - Iniciando EcomProd... 2024-01-21
20:44:23 [Link] - Inicio... 2024-01-21
20:44:23 DEBUG [Link] – Eliminar... 2024-
01-21 20:44:23 DEBUG [Link] – Crear...
2024-01-21 20:44:23 [Link] - Fin2024-
01-21 20:44:24 [Link] - Inicié EcomProd

A continuación, construye y ejecuta el microservicio Product Web,


como se muestra en Listing 3-36.

124
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Listado 3-36. Compilar y ejecutar microservicio web de


producto Usando scripts

(base) binildass-MacBook-Pro:02-ProductWeb binil$


pwd/Users/binil/binil/code/mac/mybooks/docker-
04/Code/ch03/ch03-03/02-ProductWeb(base) binildass-
MacBook-Pro:02-ProductWeb binil$ sh [Link][INFO]
Escaneando proyectos... [INFO]... binildass-MacBook-
Pro:02-ProductWeb binildass$binildass-MacBook-Pro:02-
ProductWeb binil$ sh [Link]... 2024-01-21 20:46:04 INFO
[Link] - Iniciando EcomProd... 2024-01-21
20:46:05 INFO [Link] - Start2024-01-21
20:46:05 DEBUG [Link] - Do Nothing2024-
01-21 20:46:05 INFO [Link] - End2024-01-
21 20:46:06 INFO [Link] - Iniciado
EcomProd.......

Ahora que ambos microservicios están operativos, puedes probar los


microservicios.

Pruebas del Microservicio


Una vez que ambos microservicios estén operativos, puedes inspeccionar
tu servidor MongoDB usando el terminal Mongo para asegurarte de que
el microservicio ProductServer insertó algunos productos en el servidor
MongoDB durante el arranque del microservicio. Ver Listado 3-37.

125
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Listado 3-37. Inspección del servidor MongoDB usando un shell Mongo

> [Link](){ "_id" :


ObjectId("61a71908b1690955cc51afff"), "name": "Kamsung
Mobile", "code": "KAMSUNG-TRIOS", "title" :"Tablet Trios 12
pulgadas, negro, 12 px ....", "precio" : 12000, "categoría" :
"Móvil", "_class" : "[Link]" }
{ "_id" : ObjectId("61a71908b1690955cc51b000"), "name" :
"LokiaMobile", "code" : "LOKIA-POMIA", "title" : "Lokia 12
pulgadas, blanco, 14px ....", "precio" : 9000, "categoría" :
"Mobile", "_class" : "[Link]"
}{ "_id" : ObjectId("61a71908b1690955cc51b001"), "name"
:"Mapple Mobile", "código": "MAPPLE-EPHONE", "título":
"Mapple7 pulgadas, morado, 14px ....", "precio" : 8000,
"categoría" : "Móvil", "_class" :
"[Link]" }{ "_id" :
ObjectId("61a71908b1690955cc51b002"), "name" :"Mapple
Tablet", "code" : "MAPPLE-PAD", "title" : "Mapple11 pulgadas,
gris, 140px ....", "precio" : 19000, "categoría" :"Tablet",
"_class" : "[Link]" }>
[Link](){ "_id" :
ObjectId("61a71908b1690955cc51affd"), "nombre" :"Móvil",
"título": "Móviles y Tableta", "descripción": "Teléfonos
móviles", "imgUrl": "[Link]", "_class" :
"[Link]" }{ "_id" :
ObjectId("61a71908b1690955cc51affe"), "nombre" :"Tablet",
"título": "Tablets", "descripción": "Tabletpads", "imgUrl":
"[Link]", "_class" : "[Link]"
}>

126
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Cuando todo esté listo, puedes acceder a la aplicación web desde tu


navegador. Apunta a esta URL: [Link]

Para probar las operaciones CRUD, siga las instrucciones descritas en la


subsección "Probar los microservicios usando la interfaz de usuario" en la última
sección del Capítulo 1, titulado "Su primer microservicio en Java." Antes de
probar más métodos, hagamos una pausa para inspeccionar algunos otros aspectos.
Cuando disparas esta URL en el navegador, debes prestar atención al terminal
de microservicio Web de Producto, como se muestra en la Lista 3-38.

Listado 3-38. Inspección del terminal de microservicios web del producto

... 2024-01-21 20:47:47 INFO


[Link] - Start2024-
01-21 20:47:47 INFO
[Link] - Start. Soy
instancia:
[Link]@52
8729a92024-01-21 20:47:47 INFO
[Link] -
Terminando... 2024-01-21 20:47:47 INFO
[Link] - Terminando...

Como siguiente paso, prueba el puerto basado en GraphQL. En un


terminal de comandos, ejecuta un comando cURL dirigido al puerto
GraphQL, como se muestra en el Listado 3-39.

Listado 3-39. Solicitud cURL al punto final de GraphQL

curl --request POST 'localhost:8080/graphql' --header'Content-


Type: application/json' --data-raw
'{"query":"query{products(count: 2, offset: 0) {codeNombre de
productoId}}"}'

127
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

De nuevo, debes prestar atención al microservicio web de productos,


como se muestra en el Anuncio 3-40.

Listado 3-40. Inspección del terminal de microservicios web del producto

... 2024-01-21
20:51:05 INFO ProductGraphQLController.
productos:54 - Start2024-
01-21 20:51:05 INFO [Link] - Comienzo
2024-01-21 20:51:05 INFO ProductoNegocioServicio.
getAllProducts:64 - Empezar. Soy instancia:
[Link]@528729a920
24-01-21 20:51:05 [Link]
- Terminando... 2024-01-21 20:51:05
[Link] - Terminando...

Como se ha mencionado, puedes ver en el microservicio de la Web del Producto


que las instancias del servicio de negocio del producto se agrupan o reutilizan
independientemente del puerto que la solicitud del cliente esté llevando al servidor.
Puedes ejecutar más variantes de esta petición usando los comandos
cURL en la lista 3-41.

Listado 3-41. Más solicitudes cURL al punto final de GraphQL

curl --request POST 'localhost:8080/graphql' --


header'Content-Type: application/json' --data-raw
'{"query":"query{products(count: 2, offset: 0) {codeProductId
codeCategory{id name title}}}"}'curl --request POST
'localhost:8080/graphql' --header'Content-Type:
application/json' --data-raw '{"query":"query{products(count:
2, offset: 0) {codeProductId codeCategory{id name products
{productId}}}}"}'

128
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Alternativamente, accede a la interfaz de GraphiQL desde


esta URL: [Link]

Lanza esta Solicitud para obtener la respuesta en la interfaz de


GraphiQL (véase Figuras 3-4):{products(count: 2, offset: 0)
{codeNombre de productId}}

Figura 3-4. Consulta de primer nivel de GraphiQL

A continuación, puedes lanzar la siguiente solicitud para obtener una respuesta


más detallada en la interfaz de GraphiQL (ver Figura 3-5):{products(count: 2,
offset: 0) {codeProductId codeCategory{id name title}}}

129
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Figuras 3-5. Consulta de dependencias de primer nivel de GraphiQL

Se puede recibir una respuesta detallada adicional en la interfaz de GraphiQL


mediante esta solicitud (véase Figura 3-6):{products(count: 2, offset: 0)
{productId code productCategory{id name products {productId}}}}

130
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

Figuras 3-6. Consulta de dependencia de segundo nivel de GraphiQL

Observa los registros del lado del servidor cuando ejecutes estas consultas. Será
evidente que la única consulta del dispositivo cliente está asignada a múltiples
llamadas internas del lado del servidor. Si alternas el envío de peticiones al
RESTController y al Controlador GraphQL que forma los anillos cebolla exteriores,
también puedes identificar a partir de los registros del lado del servidor que la clase
Service (y

131
Capítulo 3 OniOn y arquitectura hexagonal en la práctica

De hecho, las clases de entidades) que forman los anillos de cebolla


interiores y sus instancias se están reutilizando. ¡Aquí tienes la arquitectura
de Onion en acción!

Resumen
Comencé este capítulo analizando cómo la naturaleza conectable de los
adaptadores de puertos y adaptadores entra en juego en aplicaciones
empresariales, mostrando la conexión de un MongoDB en lugar de
PostgreSQL. Este plugin es una característica clave de la arquitectura
hexagonal. A continuación, analizaste la naturaleza complementaria de la
arquitectura hexagonal y la Onionarchitecture. Demostré una vez más una
forma flexible de añadir informes de memoria en una arquitectura hexagonal
para que el núcleo de la aplicación permanezca intacto. Igualmente importante
es la noción de capas en la Onionarchitecture, donde las capas externas
dependen de las capas internas, y a medida que avanzas hacia las capas
internas, exploras el núcleo del dominio de negocio donde la reutilización del
núcleo es un objetivo deseable. Ahora deberías tener un conocimiento sólido de
las opciones disponibles en el paradigma de la Arquitectura de Microservicios.
Ahora estás preparado para aprender sobre los conceptos de siguiente nivel de
eventos y mensajes en microservicios, que se tratan en el Capítulo 4.

132
CAPÍTULO 4

Microservicios
orientados al mensaje
En los capítulos anteriores de este libro, viste a microservicios interactuando
entre sí y a actores humanos (usuarios finales) interactuando con el
microservicio edge usando un dispositivo cliente (un navegador). Dado que
los microservicios son de naturaleza "micro", múltiples microservicios deben
comunicarse entre sí para cumplir con funcionalidades útiles del negocio.
Estas comunicaciones entre microservicios pueden realizarse dentro de un
dominio empresarial o entre dominios empresariales.
Los microservicios son partes distribuidas de una aplicación que gestionan
múltiples procesos o servicios, a veces incluso entre múltiples servidores
o hosts o incluso en varias geografías. Cada instancia de servicio suele ser
un proceso informático. Por lo tanto, las comunicaciones entre
microservicios se realizan utilizando un protocolo de comunicación
interprocesos (IPC) como HTTP o AMQP, o mediante un protocolo
binario como TCP, dependiendo de la naturaleza de estos microservicios.
La comunicación entre microservicios usando REST es sencilla y directa.
REST, en su forma más simple, es síncrono, en el sentido de que el cliente
envía una solicitud y espera una respuesta del servicio. Por tanto, el código
cliente o el hilo del lado del cliente solo pueden continuar su tarea cuando
reciben la respuesta HTTP del servidor. Aunque esto está bien, existen
paradigmas alternativos que puedes usar para lograr inter-microservicios

© Binildas A. Christudas 2024B. A. Christudas, Microservicios 133


Java y contenedores en la nube,[Link]
0555-4_4
Capítulo 4 MiCrOservices Orientados a Mensajes

comunicación, pero de una manera más flexible y escalable. Este capítulo


introduce microservicios orientados a mensajes, mediante los cuales los
microservicios pueden comunicarse a través de esquemas de mensajería.
Este capítulo cubre los siguientes conceptos:
•Características de los microservicios

• Comunicación interservicios de estilo solicitud-respuesta


basado en REST

• La necesidad de un esquema flexible para la


comunicación entre microservicios

• Introducción a los canales de mensajería


• Comunicación entre microservicios usando canales de
mensajería

• Aportando flexibilidad al estilo de interacción de


petición-respuesta de un navegador web

Características de los microservicios


Esta sección comienza analizando las características típicas de una
microaplicación de servicios, lo que te ayudará a entender la necesidad de un
nuevo paradigma para la comunicación entre microservicios.

Los microservicios son autónomos


Sabes que los microservicios se comunican entre sí, ya que un solo microservicio
puede no ser suficiente para cubrir un caso de uso de extremo a extremo
empresarial. Al mismo tiempo, uno de los objetivos de la arquitectura de
microservicios es que cada microservicio sea autónomo y esté disponible para el
consumidor cliente, incluso cuando los demás microservicios que forman parte de

134
Capítulo 4 MiCrOservices Orientados a Mensajes

El flujo de aplicaciones de extremo a extremo está bajo o es poco saludable.


Esto se suma al principio básico de que un microservicio posee y encapsula
sus propios datos.
Cuando los microservicios se comunican usando REST en el estilo
típicamente sincrónico, se dice que se comunican de forma punto a punto.
Así, un transporte HTTP es un canal punto a punto, lo que garantiza que solo
un receptor reciba un mensaje particular (véase la Figura 4-1).

Figura 4-1. Comunicación punto a punto

La figura 4-1 representa un microservicio de Orden. La orden se crea y luego


se envía al microservicio de despacho. Cuando haces una llamada desde el
microservicio Order a los microservicios de despacho (como realizar una
solicitud HTTP para un evento de orden de despacho), esta cadena de
llamadas puede proporcionar una respuesta a una aplicación cliente. Esta
arquitectura no será lo suficientemente resistente cuando algunos de estos
microservicios fallen. Para reformular, si el microservicio proveedor no puede
responder dentro del SLA, el microservicio de consumo recibirá un error.

Los microservicios son evolutivos


Una mejor alternativa es emplear un acoplamiento lajo entre
microservicios. Puedes sustituir el canal HTTP por un canal de mensajería.
De nuevo, la cola de mensajes es punto a punto, así que necesitas usar
mensajetopics, que son uno a muchos. Los temas proporcionan semánticas
de Publicación-Suscripción, que entregan una copia de un evento concreto
a cada receptor suscrito.

135
Capítulo 4 MiCrOservices Orientados a Mensajes

En un canal de Publicación-Suscripción, un canal de entrada se divide en


canales de salida múltiple, uno para cada microservicio de suscriptor. Cuando
un evento se publica en el canal, el canal Publish-Subscribe entrega una copia
del mensaje que se entregará a cada uno de los canales de salida. Cada canal
de salida tiene solo un microservicio de suscriptor, que solo puede consumir
un mensaje una vez. De este modo, cada suscriptor solo recibe el mensaje una
vez; las copias consumidas desaparecen de sus canales. Ver Figura 4-2.

Figura 4-2. Canal de publicación-suscripción

Este canal de Publicar-Suscribirse no solo aporta más autonomía a los


microservicios individuales, sino que también permite que la aplicación de
microservicios evolucione a su propio ritmo con el tiempo. En otras
palabras, como puedes ver en la Figura 4-2, cuando la aplicación de
microservicios crece con el tiempo y necesitas añadir más microservicios,
no necesitas alterar la arquitectura existente; ¡Ni siquiera necesitas reiniciar
el despliegue de la aplicación existente!

136
Capítulo 4 MiCrOservices Orientados a Mensajes

La analogía del panal


Las discusiones hasta ahora nos llevan a la analogía de un panal para la
arquitectura de microservicios. La arquitectura de la aplicación de microservicios
comienza a crecer desde el primer microservicio único hasta muchos más
microservicios, igual que se construye un panal (véase la Figura 4-3).

Figura 4-3. Analogía del panal de microservicios

La siguiente sección analiza la infraestructura de mensajería como medio para


la comunicación inter-microservicios.

Asíncrono, sigue siendo petición-respuesta


Omití intencionadamente otro aspecto importante en la sección anterior, que es
la necesidad de tener semántica de Solicitud de Respuesta para la comunicación
típica entre microservicios. Los canales de mensajería son asincrónicos,
normalmente unidireccionales o solo por solicitud. ¿Cómo recibes entonces la
respuesta correspondiente? Esta sección trata este problema.

Solicitud asíncrona
Los canales HTTP no solo son síncronos, sino que también proporcionan un
mecanismo para que el remitente reciba una respuesta o respuesta. Sin embargo, como
se ha discutido, para aprovechar al máximo los beneficios de una arquitectura basada
en mensajes, la
137
Capítulo 4 MiCrOservices Orientados a Mensajes

El mecanismo de delegación de eventos debe ser inherentemente asíncrono. Sin


embargo, puede haber muchos casos de uso en los que aún se necesite una petición-
respuesta sincrónica. El reto es entonces imitar la petición-respuesta semántica
sobre canales de mensajes, que de otro modo son canales unidireccionales.

Solicitud-Respuesta Asíncrona
Cuando una aplicación envía un mensaje, ¿cómo puede obtener una
respuesta correspondiente del receptor a través de canales de mensajería? El
patrón de Integración Empresarial Request-Reply proporciona un
mecanismo probado para el intercambio de mensajes de estilo síncrono a
través de canales asíncronos (véase la Figura 4-4).

Figura 4-4. Solicitar respuesta por asíncrona

La solución es enviar un par de mensajes de solicitud-respuesta, cada uno en


su propio canal. Sin embargo, hay un problema. Un proveedor de servicios o
un receptor (o un microservicio de rol de servidor) puede aceptar solicitudes en
un canal conocido que puede anunciar. ¿Pero qué pasa con la dirección del
canal de un cliente? Varios clientes pueden conectarse al mismo proceso de
microservicio en el rol de servidor, y no es posible que el servidor conozca o
recuerde el canal de respuesta, ya que los clientes van y vienen y pueden
aparecer muchos más nuevos en el futuro. En su lugar, una forma probada es
que el mensaje de solicitud contenga una dirección de retorno que indique
dónde enviar el mensaje de respuesta (véase la Figura 4-5).

138
Capítulo 4 MiCrOservices Orientados a Mensajes

Figura 4-5. Patrón de dirección de retorno

Al adjuntar la dirección de remitente junto con la solicitud, el respondedor no


necesita saber ni recordar dónde enviar la respuesta. Puede simplemente
inspeccionar e inferir eso a partir de la solicitud. Si diferentes mensajes al mismo
respondedor requieren respuestas en distintos lugares, el respondedor puede
inferir dónde enviar la respuesta correspondiente para cada solicitud. Esto
resume el conocimiento de qué canales usar para solicitudes y respuestas dentro
del solicitante, por lo que esas decisiones no tienen que estar codificadas
directamente en el respondedor. Una dirección de retorno se coloca en la
cabecera de un mensaje porque no forma parte de los datos que se transmiten, y
la infraestructura de transporte de mensajes no necesita inspeccionar la carga útil.
La siguiente sección demuestra este proceso en código.

139
Capítulo 4 MiCrOservices Orientados a Mensajes

Sincronización sobre microservicios asíncronos


En este ejemplo, ajustarás el mismo conjunto de microservicios que viste
antes. Un microservicio consumidor y un proveedor se comunicarán entre sí
mediante un canal de mensajería. El microservicio del proveedor almacena
la entidad en una base de datos en memoria para mantener el ejemplo simple.

Diseño de microservicios sobre canal asíncrono


Este ejemplo modifica ligeramente la vista hexagonal de microservicios
mostrada en la Figura 2-1 del Capítulo 2 para que ambos microservicios se
comuniquen a través de un canal de mensajería asíncrono en lugar del canal
HTTP. Apache Kafka se utiliza como canal de mensajería, que es inherentemente
yasíncrono. Recuerda, el objetivo es simular una comunicación de estilo
síncrono a través del canal asincrónico basado en Kafka. Véase la Figura 4-6.

Figuras 4-6. Los microservicios se comunican a través del canal asíncrono

La solicitud del usuario final desde el navegador llegará primero al microservicio


web del producto. El microservicio Web del Producto delegará la solicitud al
microservicio del Servidor del Producto, pero a través de un canal de mensajes.

140
Capítulo 4 MiCrOservices Orientados a Mensajes

El microservicio Product Server podría saber automáticamente qué canal


enviar respuestas al microservicio Product Web, pero como se ha comentado
antes, las suposiciones codificadas hacen que el software sea menos flexible y
más difícil de mantener. En este caso, una única instancia de microservicio de
Product Server podría estar procesando llamadas de varios tipos diferentes de
solicitantes y/o incluso de múltiples instancias del mismo tipo de solicitante,
por lo que el replychannel no es el mismo para todos los mensajes. Depende
de qué solicitante haya enviado ese mensaje de solicitud. En este caso, puedes
usar el patrón de dirección de retorno.
Ten en cuenta que el microservicio Product Server en este ejemplo utiliza un puerto
de mensajería, en contraste con el puerto HTTP usado en ejemplos anteriores. Esto
valida aún más el aspecto de cómo diferentes puertos y adaptadores en la
arquitectura hexagonal pueden conectarse fácilmente, cuando sea necesario.

Entendiendo el Código
El código fuente de este libro está disponible en GitHub a través de la página
de producto del libro, ubicada en [Link]/9798868805547. El código
de este ejemplo está organizado dentro de la carpeta ch04\ch04-01. Esta
sección analiza primero los cambios en el microservicio del consumidor —es
decir, el microservicio Web del Producto.
El componente central utilizado es RespondingKafkaTemplate<K,V,R>
fromSpring, que extiende el comportamiento de una KafkaPlantilla para
proporcionar semántica de petición-respuesta. Para configurarlo, necesitas un
productor (ProducerFactory) y un KafkaMessageListenerContainer. El listado
4-1 muestra cómo hacer esto usando una clase de Configuración de Kafka.

141
Capítulo 4 MiCrOservices Orientados a Mensajes

Listado 4-1. Configuración Kafka para Message Producer (ch04\ch04-


01\02-
ProductWeb\src\main\java\com\acme\ecom\product\[Link])

@Configurationpublic
class KafkaConfig {

@Beanpublic Map<String, Object>


producerConfigs() {
config values va aquí}@Beanpublic
Map<String, Object> consumerConfigs() {

config values aquí}@Beanpublic


ProducerFactory<String, String> producerFactory() {

volver nuevo DefaultKafkaProducerFactory<>(


producerConfigs());
}@Beanpublic KafkaTemplate<String, String>
kafkaTemplate() {

return new KafkaPlantilla<>


(producerFactory());}@Beanpublic
RespondiKafkaPlantilla<cadena, cadena, productos>

replyKafkaPlantilla(ProducerFactory<String,
String> pf, KafkaMessageListenerContainer<String,
Products> container){

142
Capítulo 4 MiCrOservices Orientados a Mensajes

return new RespondlyingKafkaTemplate<>(pf,


contenedor);}@Beanpublic
KafkaMessageListenerContainer<String, Products>

respondenContenedor(ConsumidorFábrica<Cadena,
Productos> cf)
{PropiedadesContenedorPropiedades =nuevas
PropiedadesContenedor(solicitudTemaRespuesta);
return new KafkaMessageListenerContainer<>(cf,
Propiedades de contenedores);
}@Beanpublic ConsumerFactory<String,
Productos>

consumerFactory() {return new


DefaultKafkaConsumerFactory<>(
consumerConfigs(),new
StringDeserializer(),new JsonDeserializer<>(
[Link]));
}@Beanpublic
KafkaListenerContainerFactory<

ConcurrentMessageListenerContai
ner<String, Productos>>
kafkaListenerContainerFactory() {

ConcurrentKafkaListenerContainerFactory<String,
Productos> fábrica =nuevo
ConcurrentKafkaListenerContainerFactory<>();

143
Capítulo 4 MiCrOservices Orientados a Mensajes

[Link]ábrica(consumidorFábric
a));
[Link](kafkaPlantilla(
)); Fábrica de retorno;}@Beanpublic
KafkaAdmin admin() {

Map<String, Object> configs = new HashMap<>();


[Link](ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,
bootstrapServers); return new
KafkaAdmin(configs);}@Beanpubli
c NewTopic requestTopic() {

Map<String, String> configs = nuevo HashMap<>();


[Link]("[Link]", [Link]());
devolver nuevo Nuevo Tema(requestRespondlyTopic, 2, (corto) 1).
configs(configs);
}}

Para entender la mecánica del transporte de eventos, considera cómo será un


evento típico (es decir, un mensaje):

Clave del evento: "Ria" Valor del evento: "Realizó un pago de 300 $ a Ann"
Marca de tiempo del evento: "25 de septiembre de 2021 a las 15:06" Existe un
originador para un evento, y los eventos suelen ser datos de series temporales.
Si miras la plantilla para enviar un evento, theReplyingKafkaTemplate <K, V,
R> ofrece un objeto return o un reply una vez que el mensaje es consumido
por el oyente Kafka desde el lado proveedor o productor. Los parámetros de
tipo representan:

144
Capítulo 4 MiCrOservices Orientados a Mensajes

•K – El tipo de clave

•V – El tipo de dato saliente

•R – El tipo de dato de respuesta Aquí, la marca de tiempo del evento


mostrada en el evento de ejemplo podría ser un encabezado de metadatos
opcional. Las claves se utilizan para determinar la partición en alog en la
infraestructura de mensajería a la que se añade un mensaje. Valuees la carga
útil real del mensaje. Cuando se publica un nuevo evento en atopic, se añade a
una de las particiones del tema. Los eventos con la misma clave de eventos
(por ejemplo, un ID de cliente o ID de cuenta) se escriben en la misma
partición, y Kafka garantiza que cualquier consumidor de una partición de
tema dada siempre leerá los eventos de esa partición en el mismo orden en
que fueron escritos. La clave y/o el valor también pueden ser nulos. Si la clave
es nula, entonces se seleccionará una partición aleatoria. Si el valor es nulo,
puede tener semántica especial de "eliminación" si activas la política de
compactación de logs en lugar de la política de retención de logs para un
tema. Usar la clave para dirigir a una partición es la estrategia predeterminada
del productor. Especificar la clave para que todos los eventos en la misma
clave vayan a la misma partición es importante para un orden correcto del
procesamiento de mensajes, si tienes varios consumidores en un grupo de
consumidores1 sobre un tema. Sin akey, dos mensajes en la misma clave
podrían ir a particiones diferentes y ser procesados por distintos consumidores
del grupo, fuera de orden. En última instancia, el productor elige qué partición
usar. Si especificas el parámetro de partición, se usará y la clave será
"ignorada" aunque siga escrita en el tema. Esto te permite tener una
personalización

1 Un grupo de consumidores Kafka es un conjunto de consumidores que


cooperan para consumir datos de ciertos temas. Las divisiones de todos los
temas se dividen entre los consumidores del grupo.

145
Capítulo 4 MiCrOservices Orientados a Mensajes

Particionar incluso si tienes claves. En otras palabras, las garantías del orden no
provienen de la clave, sino de que los mensajes estén en la misma partición.
Torestate, el enrutamiento de mensajes a particiones no tiene por qué ser basado en
claves. Puedes especificar explícitamente una partición al crear un ProducerRecord.
Este ejemplo define el bean como RespondiKafkaPlantilla<Cadena, Cadena,
Productos>, donde enviarás una solicitud tipo String a Kafka y luego obtendrás
el objeto tipo Products como tipo de respuesta. Crearás los Productos y las
clases DTO incluidas en la siguiente sección. En resumen, configuras una
plantilla de respuesta Kafka que envía mensajes de solicitud con claves de
cadena y recibe mensajes de respuesta con claves de cadena. La plantilla
RespondingKafka debe estar respaldada por una FactorProductora de Solicitud, una
FactoríaConsumidora de Respuesta y un ContenedorEscuchadorMensaje, con las
correspondientes configuraciones de consumidor y productor, lo cual se hizo en
el Administrador Kafka en la Lista 4-1.

Cuando defines un bean KafkaAdmin en el contexto de la aplicación, puede


añadir automáticamente temas al broker. Para ello, necesitas añadir un
@Bean de NewTopic para cada tema al contexto de la aplicación.
Las Propiedades del Contenedor contienen propiedades en tiempo de ejecución
para el contenedor alistener. Aunque especifiques la dirección de respuesta
usingrequestReplyTopic, más adelante verás que este ejemplo establece
explícitamente thereturn address al enviar el mensaje. Crea un contenedor de
escucha de mensajes de un solo hilo usando el consumidor Java.
La clase controlador REST, que se utiliza en RespondlyingKafkaTemplate,
está configurada en KafkaAdmin en el listado 4-2.

146
Capítulo 4 MiCrOservices Orientados a Mensajes

Listado 4-2. Kafka Configuration for Message Producer (ch04\ch04-01\02-


ProductWeb\src\main\java\com\acme\ecom\product\controller\ProductRest
[Link])

@RestControllerpublic class
ProductRestController{

@AutowiredReplyingKafkaTemplate<String,
String,Products>kafkaPlantilla;@Value("${
[Link]-topic}")privado
String
requestTopic;@Value("${[Link]
treply-topic}")privado String
requestReplyTopic;@RequestMapping(value =
"/productsweb",
método = [Link],produces =
{MediaType.APPLICATION_JSON_VALUE})Public
ResponseEntity<Resources<Resource<Product>>>
getAllProducts() lanza
InterruptedException,ExecutionException
{ProducerRecord<String, String> record =
nuevo ProductorRecord<String,String>
(requestTopic, "All");
[Link]().add(nuevo RecordHeader(
KafkaHeaders.REPLY_TOPIC,requestReplyTopic
.getBytes())); RequestReplyFuture<String,
String, Products>
enviarRecibirRecibir =
[Link](record);

147
Capítulo 4 MiCrOservices Orientados a Mensajes

ConsumerRecord<Cadena, Productos> ConsumidorRegistro =


[Link]én(); return new
ResponseEntity([Link]().
getProducts(), [Link]);
}}

El controlador REST recibe las solicitudes del dispositivo cliente, en este


caso del navegador. Dentro del controlador,
therequestReplyKafkaTemplate genera y establece una cabecera
KafkaHeaders.CORRELATION_ID. El CorrelationId debe ser consumido
por el microservicio del proveedor y devolverlo en la cabecera. Necesitas
establecer explícitamente el encabezado KafkaHeaders.REPLY_TOPIC en
la petición, aunque el mismo tema de respuesta estaba redundantemente
conectado a thereplyListenerContainer en KafkaConfig antes.
El método sendAndReceive de ResponderKafkaPlantilla envía una
solicitud y recibe una respuesta con el tiempo de espera por defecto. Te da
un RequestReplyFuture, en el que puedes llamar al get, que esperará si es
necesario a que se complete el cálculo y luego recuperará su resultado.
Productos en este caso.
A continuación, mira la clase Productos. Ver Listado 4-3.

Listado 4-3. La clase contenedor para devolver la colección de


ProductEntities (ch04\ch04-01\02-
ProductWeb\src\main\java\com\acme\ecom\product\model\[Link])

Productos de clase pública {

productos privados de List<Product>;


Public List<Product> getProducts() {
Devolve
productos;}

148
Capítulo 4 MiCrOservices Orientados a Mensajes

public void setProducts(List<Product> products) {


[Link] = products;}}

Products es simplemente un envoltorio de contenedor que


contiene una colección de Productinstances.
La configuración de microservicios Web del Producto se muestra en los
Listados 4-4, donde el tema requestreply-topic se refiere al tema al que el
proveedor debe enviar la respuesta.

Listado 4-4. La configuración de microservicios web del producto


(ch04\ch04-01\02-
ProductWeb\src\main\resources\[Link])

[Link]=[Link]-servers:
localhost:[Link]-offset-
reset: [Link]-id:
[Link]-topic:
[Link]-
topic=[Link]-
[Link]-ms: 20000

En el lado de los microservicios del Product Server, un KafkaListener


regular está escuchando el tema de la solicitud. Ver Listado 4-5.

Listado 4-5. La configuración de microservicios web del producto (ch04\ch04-01\01-


ProductServer\src\main\java\com\acme\ecom\product\kafka\client\[Link]
)

@Componentpublic clase
ProductListener {

@KafkaListener(topics = "${[Link]-
topic}")@SendTo

149
Capítulo 4 MiCrOservices Orientados a Mensajes

Public Products listen(Solicitud de cadena) {

Lista<Product> productoLista =
getAllTheProducts(); Productos productos =
productos nuevos();
[Link](ListaProducto); devolver
productos;}}

Este oyente está decorado con una anotación @SendTo adicional para
proporcionar el mensaje de respuesta. Las instancias Product recuperadas por
el método getAllTheProducts() y devueltas por el método del oyente se
envuelven automáticamente en un mensaje de respuesta. Se añade el
CORRELATION_IDis y la respuesta se publica sobre el tema especificado
por el REPLY_TOPIC. El @KafkaListener se utiliza para suscribirse a la
solicitud Kafkatopic. Usando la anotación, la anotación de @SendTo permite
que el método listener envíe una respuesta a otro tema de respuesta. Las
figuras 4-7 ilustran la dinámica de estas interacciones y está marcada con
etiquetas en orden del flujo de eventos.

Figuras 4-7. Plantilla de Kafka de respuesta

También tienes un KafkaConfig para el microservicio del proveedor, pero es


simple y directo comparado con el microservicio para consumidores, así que
no está listado aquí.

150
Capítulo 4 MiCrOservices Orientados a Mensajes

Construye y ejecuta el microservicio


La carpeta ch04\ch04-01 contiene los scripts Maven necesarios para construir
estos ejemplos. Como primer paso, necesitas mencionar al intermediario
Kafka. Consulta el Apéndice D para aprender a configurar el servidor Kafka y
abrirlo. Tienes que ejecutar los comandos en la lista 4-6 para abrir a Kafka
desde la ubicación de Kafkainstalación.

Listados 4-6. Órdenes para sacar a relucir a Kafka Broker

bin/[Link] config/[Link]/kafka-
[Link] config/[Link]

A continuación, toma dos terminales de comandos y cambia el directorio a


la carpeta de nivel superior de ambos microservicios. Luego, compila y
ejecuta el microservicio ProductServer usando los scripts [Link] y
[Link], como se muestra en Listing 4-7.

Listados 4-7. Comandos para construir y ejecutar el


microservicio Product Server

(base) binildass-MacBook-Pro:01-ProductServer binil$


pwd/Users/binil/binil/code/mac/mybooks/docker-
04/Code/ch04/ch04-01/01-ProductServer(base) binildass-
MacBook-Pro:01-ProductServer binil$ sh [Link][INFO]
Escaneando proyectos... [INFO]... binildass-MacBook-
Pro:01-ProductServer purchased$binildass-MacBook-Pro:01-
ProductServer purchased$ sh [Link]

151
Capítulo 4 MiCrOservices Orientados a Mensajes

. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \(
( )\___ | '_ | '_| | '_ \/ _` | \ \ \
\\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / /
/=========|_|==============|___/=/_/_/_/:: Bota de
Resorte ::(v3.2.0)2024-01-23 11:43:59
[Link] - Iniciando EcomProd... 2024-01-23
11:44:00 [Link] - Start2024-01-23
11:44:00 [Link] - No hacer nada...
2024-01-23 11:44:00 [Link] -
Fin2024-01-23 11:44:01 [Link] - Iniciado
EcomProd2024-01-23 11:56:03 DEPURAR
[Link] - Solicitud
recibida: Todos...

A continuación, construye y ejecuta el microservicio Product Web,


como se muestra en Listing 4-8.

Listados 4-8. Comandos para construir y ejecutar el producto


WebMicroservice

(base) binildass-MacBook-Pro:02-ProductWeb binil$


pwd/Users/binil/binil/code/mac/mybooks/docker-
04/Code/ch04/ch04-01/02-ProductWeb(base) binildass-
MacBook-Pro:02-ProductWeb binil$ sh [Link][INFO]
Escaneando proyectos... [INFO]...

152
Capítulo 4 MiCrOservices Orientados a Mensajes

binildass-MacBook-Pro:02-ProductWeb binil$binildass-
MacBook-Pro:02-ProductWeb binil$ sh [Link]... 2024-01-
23 11:54:08 INFO [Link] -
Iniciando EcomProductWebMicro...... 2024-01-23
11:54:10 INFO [Link] -Inicié
EcomProductWebMicro...

Ahora que ambos microservicios están operativos, puedes probar los


microservicios.

Pruebas del Microservicio


Cuando todo esté listo, puedes acceder a la aplicación web usando tu
navegador (véase las Figuras 4-8). Señala esta URL:

[Link]

Figuras 4-8. Pruebas de los microservicios

153
Capítulo 4 MiCrOservices Orientados a Mensajes

Cuando disparas la URL en el navegador, la solicitud llega al RESTcontroller


del microservicio Web del producto. A partir de entonces, el flujo se muestra
en las figuras 4-7.
Para mayor detalle de este ejemplo, también puede que quieras listar y ver las
colas de solicitudes y respuestas creadas en el broker, como se muestra en la
Lista 4-9.

Listados 4-9. Lista las colas creadas en Kafka Broker

binildass-MacBook-Pro:kafka_2.13-2.5.0 binil$ sh
./bin/[Link] --zookeeper localhost:2181 --
list__consumer_offsetsproduct-req-req-reply-
topicproduct-req-topicbinildass-MacBook-Pro:kafka_2.13-
2.5.0 binil$

SEDA y Microservicios
Tras debatir y ejecutar ejemplos sobre cómo puedes realizar comunicaciones
inter-microservicios a través de una columna vertebral de mensajería asincrónica,
ahora es momento de entender el panorama general de a qué te diriges. El
concepto SEDA (Arquitectura Impulsada por Eventos Escalonados) se utiliza
para permitir que los servicios estén bien condicionados para ser cargados,
evitando que los recursos se sobrecomprometan cuando la demanda supera la
capacidad de servicio. Investigarás eso a continuación y transmitirás el concepto
a tus microservicios empresariales usando infraestructura de mensajería.

Arquitectura SEDA
En SEDA, las aplicaciones consisten en una red de etapas impulsadas por eventos
conectadas por colas explícitas. Esta arquitectura permite que los servicios estén bien
condicionados para cargar, evitando que los recursos se sobrecomprometan cuando
la demanda supera la capacidad de servicio. SEDA utiliza un conjunto de dinámicas

154
Capítulo 4 MiCrOservices Orientados a Mensajes

controladores de recursos para mantener las etapas dentro de su régimen


operativo, a pesar de grandes fluctuaciones en la carga. Esto se explica en el
artículo titulado "SEDA: Una arquitectura para servicios de Internet bien
condicionados y escalables" de Matt Welsh, David Culler y Eric Brewer. La
arquitectura se muestra en las Figuras 4-9, adaptadas de este artículo.

Figuras 4-9. Una etapa SEDA

Una etapa consta de una cola de eventos entrantes, un pool de hilos y un


gestor de eventos suministrado por una aplicación. La operación de la etapa es
gestionada por el controlador, que ajusta dinámicamente la asignación de
recursos y la programación. Muchas de estas etapas pueden encadenarse para
crear un continuo de aplicaciones de extremo a extremo débilmente acoplado.

155
Capítulo 4 MiCrOservices Orientados a Mensajes

Arquitectura de microservicios como


red de etapas
Una arquitectura basada en microservicios puede diseñarse como una red de etapas,
interconectadas por colas de eventos. Cada microservicio puede concebirse como un
escenario. Estas colas de eventos son finitas; es decir, una operación de enqueue
puede fallar si la cola quiere rechazar nuevas entradas, por ejemplo, porque ha
alcanzado un umbral. Los microservicios de llamadas pueden usar contraataque
(bloqueando en una cola completa) o cortes de carga (eliminando eventos) cuando las
operaciones de enqueue fallan. Alternativamente, los microservicios pueden realizar
alguna acción específica del servicio, como enviar un error al usuario o realizar una
función alternativa, como invocar una callback de Hystrix, y así sucesivamente.
¿Y si intentas representar la interacción entre microservicios usando el estilo
aSEDA? Ver Figura 4-10.

Figuras 4-10. Arquitectura de microservicios basada en asíncronas


como red de etapas

Introducir colas entre dos microservicios de esta manera proporcionará


aislamiento, modularidad y gestión independiente de cargas, pero puede aumentar
la latencia. Además, si el microservicio del proveedor no está operativo, la
promesa que el microservicio al consumidor puede ofrecer hasta el final

156
Capítulo 4 MiCrOservices Orientados a Mensajes

puede que el usuario tenga que ser satisfecho más adelante (o


eventualmente), lo que conducirá a una experiencia de usuario diferente a la
de los medios tradicionales de ejecutar casos de uso.
Observa la forma de bloqueo en que el microservicio Web de Producto ha estado
ejecutando la solicitud que recibió del navegador. Los contenedores típicos en
servidores de aplicaciones como en Apache Tomcat normalmente usan una solicitud
cliente de hilos de servidor. En condiciones de carga elevadas, esto requiere que los
contenedores tengan muchos hilos para atender todas las solicitudes del cliente.
Esto limita la escalabilidad, que puede deberse a quedarse sin memoria o agotar el
conjunto de hilos contenedor. Java EE ha añadido soporte para procesamiento
asíncrono para servlets y filtros a partir de la especificación Servlet 3.0.
La siguiente sección te muestra cómo puedes aprovechar esto para
aislar recursos de bloqueos indebidos con la ayuda de un ejemplo.

HTTP asíncrono sincronizado


sobre microservicios asíncronos
En este ejemplo, modificarás el mismo conjunto anterior de microservicios
utilizado en este capítulo. Un microservicio consumidor y un proveedor se
comunicarán entre sí mediante un canal de mensajería. El proveedor
microgestiona la entidad en una base de datos en memoria, para simplificar el
ejemplo. Además, cuando el navegador envía una petición al primer microservicio
(consumidor), el ejemplo usará HTTP asíncrono en lugar de HTTP sincronizado.

Entendiendo el Código
El código fuente de este libro está disponible en GitHub a través de la página
de producto del libro, ubicada en [Link]/9798868805547. El código
fuente de este ejemplo está organizado dentro de la carpeta ch04\ch04-02. La
lista 4-10 analiza primero los cambios en el microservicio de consumo —es
decir, el microservicio Web de Producto.

157
Capítulo 4 MiCrOservices Orientados a Mensajes

Listados 4-10. Product Web Microservice REST Controller (ch04\ch04-02\02-


ProductWeb\src\main\java\com\acme\ecom\product\controller\ProductRestCo
[Link])

public class ProductRestController{

@RequestMapping(value = "/productsweb",
método =[Link],
produce = {MediaType.APPLICATION_JSON_VALUE})public
DeferredResult<Products> getAllProducts()
lanza InterruptedException, ExecutionException
{[Link]("Start"); [Link]("Thread : "
+ [Link]()); <Products>
ResultadoDeferredResultadoAplazado =
nuevo DeferredResult<>();
ProductorGrabación<Cuerda, Cuerda> grabación =
nuevo productorGrabación<Cuerdas, Cuerdas>(
requestTopic, "Todos");
[Link]().add(nuevo RecordHeader(
KafkaHeaders.REPLY_TOPIC,requestReplyT
[Link]()));
[Link]().forEach(encabezado ->
[Link]([Link]() + ":"
+[Link]().toString()));
RequestReplyFuture<String, String, Products>
enviarY Recibir
=[Link](record)
; SendResulta<Cadena, Cadena> enviarResultadT=
[Link]().recibir();

158
Capítulo 4 MiCrOservices Orientados a Mensajes

[Link]("Solicitud de éxito -> " + sendResult);


[Link]().encabezados().forEach(
encabezado -> [Link]([Link]() + " " : " +
new String([Link]())));

[Link](
nuevo ListenableFutureCallback<
ConsumerRecord<String, Products>>
() {@Overridepublic void
onFailure(Throwable ex) {
[Link]([Link]().
toString());
[Link]([Link]());}@O
verridepublic vacío enSuccess
(ConsumerRecord<

Cadena, Productos> consumidorRegistro) {segundos


largosToSleep = 2; [Link]("Empezando a
entrar en suspensión segundos :
" + segundosParaDormir);
try{
[Link](1000 *
segundosParaDormir);}catch(Excepción
e) {
[Link]("Error : " +
e);}[Link]("Despertando del
sueño...");
[Link]([Link]().
toString());

159
Capítulo 4 MiCrOservices Orientados a Mensajes

[Link](
[Link]());}}); [Link]("Thread : "
+ [Link]()); [Link]("Ending...");
return deferredResult;}}

Como puedes ver, el método getAllProducts en el controlador REST es


asincrónico. Esto significa que el hilo principal HTTP que inició para servir
a getAllProducts no tiene por qué ser bloqueado hasta que el método esté
completado. También hay un modo de suspensión de dos segundos para que
puedas visualizar estos métodos en el terminal de comandos.
También se incluye un sueño de seis segundos en el microservicio Product
Server, como se muestra en los Listados 4-11.

Listado 4-11. Product Server Microservice Message Listener ch04\ch04-02\01-


ProductServer\src\main\java\com\acme\ecom\product\kafka\client\ProductList
[Link])

clase pública ProductListener {

@KafkaListener(topics = "${[Link]-
topic}")@SendTopublic Productos
escuchaConsumerRecord(ConsumerRecord)<
Cuerda, cuerda> grabación)
{segundos largosToSleep =
6; [Link]("Iniciar");

160

También podría gustarte