Arquitecturas Web
Servicios REST, Spring
e Inyección de dependencias
2022
Repaso
Servidor Web
Aplicación Web
JPA
Navegador
Web
Servlets
Servicios Web
JDBC
Base de
datos
2
Servicios Web + Spring framework
Navegador
Web
Servlets
Otros
sistemas
Servicios Web
JPA
JPARepository
Aplicación
móvil
Service
REST Controller
Aplicación Web
JDBC
Base de
datos
3
Servicios Web
Funcionalidad ofrecida por un componente (ej., aplicación Web en un
servidor) a otros, a través de una API Web
●
Mecanismo de comunicación basado en protocolos Web (ej., HTTP),
como SOAP y REST
○ Independiente de la tecnología (lenguaje de implementación)
●
Transferencia de datos basada en formatos de texto,
como XML y JSON
○ Alternativa a protocolos con formatos binarios cómo Sockets, RPC, etc.
○ Menor performance pero mayor integrabilidad y modificabilidad
4
Servicios REST: principios
1. Usar los métodos HTTP explícitamente como acciones sobre recursos
2. Exponer recursos a través de su URL
3. Sin estado (stateless)
4. Transferir los datos de recursos mediante XML, JSON o ambos
5
Servicios REST: principios
1. Usar los métodos HTTP explícitamente como acciones sobre recursos
2. Exponer recursos a través de su URL
○ URLs como estructura jerárquica de “Endpoints”
http://www.miservicio.com/recursos/usuarios
http://www.miservicio.com/recursos/usuarios/{idUsuario}
http://www.miservicio.com/recursos/usuarios/{idUsuario}/actividades
http://www.miservicio.com/recursos/usuarios/{idUsuario}/actividades/{idActividad}
○ Se desacopla la API del servicio de su implementación
http://www.miservicio.com/usuarios.jsp
http://www.miservicio.com/actividades.php
3. Sin estado (stateless)
4. Transferir los datos de recursos mediante XML, JSON o ambos
6
Servicios REST: principios
1. Usar los métodos HTTP explícitamente como acciones sobre recursos
2. Exponer recursos a través de su URL
Endpoint (URL)
POST
GET
PUT
DELETE
/recursos
Crear un nuevo
recurso (201 Created)
Listar recursos
(200 OK)
Actualizar
simultáneamente
varios recursos
Borrar todos los
recursos
/recursos/{id}
Error (Ej. 400 Bad
request)
Si existe devolver
recurso {id}, sino error
(404 Not found)
Si existe {id} actualizar
recurso, sino error.
Borrar recurso según
{id}
3. Sin estado (stateless)
4. Transferir los datos de recursos mediante XML, JSON o ambos
7
Servicios REST: principios
1. Usar los métodos HTTP explícitamente como acciones sobre recursos
2. Exponer recursos a través de su URL
3. Sin estado (stateless)
○
○
○
Lógica del servidor más
fácil de implementar
El estado lo maneja
el cliente (o una BD)
Fácil de escalar y almacenar
en cache dentro de proxies
y clientes.
4. Transferir los datos de recursos mediante XML, JSON o ambos
8
Servicios REST: principios
1.
2.
3.
4.
Usar los métodos HTTP explícitamente como acciones sobre recursos
Exponer recursos a través de su URL
Sin estado (stateless)
Transferir los datos de recursos mediante XML, JSON o ambos.
○
Representación simple y legible
Tupla en BD
ID
Nombre
Raza
Edad
1
Homero
Labrador
5 años
XML
JSON
<?xml version="1.0" encoding="UTF-8" ?>
<perro>
<id>1</id>
<name>Homero</name>
<raza>Labrador</raza>
<edad>5</edad>
</perro>
{
"perro": {
"id": "1",
"name": "Homero",
"raza": "Labrador",
"edad": "5"
}
}
9
Manejo de Estado
●
●
Para poder escalar, es importante gestionar el estado
asociado a una sesión
El almacenamiento de estados “intermedios” tiene que ver
con:
○
○
○
○
●
Datos de autenticación
Datos relacionados con selecciones del usuario (por ej., carrito
de compras)
Datos de acciones realizadas
Contenido dinámico
La estrategia de manejo de estado
impacta en la carga del sistema
10
Manejo de Estado – Ejemplo 1
●
●
●
Consideremos la siguiente función que cuenta cuantas veces
es llamada por un cliente
La cuenta recuerda i entre una llamada y la siguiente
Se mantiene el estado dentro de la
función 🡪 stateful
11
Manejo de Estado – Ejemplo 2
●
●
●
Consideremos la siguiente función que cuenta cuantas veces
es llamada por un cliente
La cuenta no recuerda i entre una llamada y la siguiente. El
cliente debe pasar el último valor
Se le pasa estado a la función 🡪 stateless
12
Manejo de Estado – Ejemplo 3
●
●
●
Consideremos la siguiente función que cuenta cuantas veces
es llamada por un cliente
La cuenta se almacena en una base de datos
Ni el cliente ni la función recuerdan el valor
🡪 stateless
13
JAX-RS y Jersey
• JAX-RS (Java API for RESTful Web Services):
API estándar de Java para construir servicios con interfaz REST
• Jersey: Implementación de referencia de JAX-RS
<<API>>
JAX-RS
<<API>>
JPA
<<API>>
JDBC
REST
EasyJersey
EclipseLink
OpenJPA
Hibernate
DriverDriver
x
DriverDerby
MySQL
14
Anotaciones JAX-RS
import javax.ws.rs.*
Para mapear requests HTTP a métodos Java:
Para extraer información del request:
@Path(“/path”)
@PathParam(“param”)
@GET, @PUT, @POST, @DELETE, @HEAD
@QueryParam(“param”)
@Produces(MediaType.X)
@MatrixParam(“param”)
@Consumes(MediaType.X)
@HeaderParam(“param”)
MediaType.APPLICATION_JSON
@CookieParam(“param”)
MediaType.APPLICATION_XML
@FormParam(“param”)
MediaType.TEXT_HTML
@DefaultValue(“value”)
MediaType.TEXT_PLAIN
@Context
15
Proyecto con JPA y JDBC
Recurso
Recurso
Entidad
REST
REST
(Plain
Old
Java Object)
App
(Main.java,
JUnit)
JPA/JDBC
Recurso
Recurso
REST
DAO
REST
JPA
Provider
+
JDBC
Driver
persistence.xml
Base de
datos
16
Proyecto Web con Spring, JPA y JDBC
Recurso
Recurso
Entity
REST
REST
(Plain
Old
Java Object)
HTTP Servicios
REST
Cliente
REST
Recurso
Recurso
REST
REST
REST
Controller
Service
Recurso
Recurso
REST
Repository
REST
JPA/JDBC
JPA
Provider
+
JDBC
Driver
Base de
datos
Contenedor Web (Tomcat/Spring …)
17
Entidades (POJOs) con anotaciones JPA
@Entity
public class Usuario {
@Id @GeneratedValue
int id;
String nombre;
Recurso
Recurso
REST
Entity
REST
(POJO)
String apellido;
public int getId() {
return id;
}
Recurso
Recurso
REST
REST
REST
Controller
Recurso
Recurso
REST
Repository
REST
…
}
18
Repositorio (o Data Access Object – DAO)
public class UsuarioRepository {
EntityManager entityManager;
public Usuario findById(int id) {
Usuario usuario= entityManager.find(Usuario.class, id);
Recurso
Recurso
REST
Entity
REST
(POJO)
return usuario;
}
public void persist(Usuario usuario) {
entityManager.getTransaction().begin();
entityManager.persist(usuario);
Recurso
Recurso
REST
REST
REST
Controller
Recurso
Recurso
REST
Repository
REST
entityManager.getTransaction().commit();
}
…
}
19
Repositorio: Generalizando funcionalidad
<<Interface>>
Repository
public interface Repository<Entity , ID extends Serializable> {
public Entity findById(ID id);
public Entity persist(Entity entity);
public Entity delete(ID id);
public List<Entity> findAll();
BaseJPARepository
}
UserRepository
MeetingRepository
20
Repositorio: Generalizando funcionalidad
public class BaseJPARepository<Entity, ID extends Serializable>
implements DAO<Entity, ID>{
<<Interface>>
Repository
EntityManager entityManager;
Class<Entity> entityClass;
Class<ID> idClass;
public BaseJPARespository(Class<Entity> entityClass,Class<ID> idClass) {...}
BaseJPARepository
public Entity findById(int id) {
Entity entity = entityManager.find(entityClass, id);
return entity;
}
public void persist(Entity entity) {
UserRepository
MeetingRepository
entityManager.getTransaction().begin();
entityManager.persist(entity);
entityManager.getTransaction().commit();
}
…
21
Repositorio: Generalizando funcionalidad
<<Interface>>
Repository
public class UserRepository extends BaseJPARepository<User,Integer>{
public UserRepository(){
super(User.class , Integer.class);
BaseJPARepository
}
public List<User> findUsersByName(String name){...}
}
UserRepository
MeetingRepository
22
Repositorio: Gestión de instancias (no Springboot)
Patrón Singleton
Patrón Factory
public class UsuarioRepository
public interface RepositoryFactory {
extends BaseJPARepository<Usuario,Integer>{
UsuarioRepository getUsuarioRepository();
OtroRepository getOtroRepository();
private static UsuarioRepository usuarioDao;
…
}
private UsuarioRepository(){
super(Usuario.class,Integer.class);
}
public class JPARepositoryFactory implements
RepositoryFactory{
public static UsuarioRepository getInstance() {
if(usuarioDao==null)
public static JPARepositoryFactory
getInstance(){...};
usuarioDao=new UsuarioRepository();
UsuarioRepository getUsuarioRepository(){...};
return usuarioDao;
OtroRepository getOtroRepository(){...};
}
…
…
}
23
Singleton EntityManagerFactory
@WebListener
public class EMF implements ServletContextListener {
private static javax.persistence.EntityManagerFactory emf;
@override
public void contextInitialized(ServletContextEvent arg) {
emf = Persistence.createEntityManagerFactory("PersistenceUnit");
}
@override
public void contextDestroyed(ServletContextEvent arg) {
emf.close();
}
public static EntityManager createEntityManager() {
if (emf == null) {
throw new IllegalStateException("Context is not initialized yet.");
}
return emf.createEntityManager();
}
}
24
REST Controller
• Mapeo de solicitudes REST a métodos Java con anotaciones
GET /api/v1/usuarios/{id}
POST /api/v1/usuarios
Recurso
Recurso
REST
Entity
REST
(POJO)
Recurso
Recurso
REST
REST
REST
Controller
Recurso
Recurso
REST
Repository
REST
GET /api/v1/usuarios/count
25
REST Controller
• Mapeo de solicitudes REST a métodos Java con anotaciones
@RequestMapping("/usuarios")
public class UsuarioController {
@RequestMapping(value=“/{id}”, method=RequestMethod.GET, produces=“application/json”)
GET /api/v1/usuarios/{id}
public Usuario getUsuarioById(@PathVariable String id) {
int _id = Integer.valueOf(id);
Usuario usuario = usuarioService.findById(_id);
return usuario; }
@RequestMapping(method=RequestMethod.POST, produces=“application/json”,
consumes: “application/json”)
POST /api/v1/usuarios
public Usuario createUsuario(Usuario usuario) {
return usuarioService.addUsuario(usuario) }
@RequestMapping(value=“/count”, method=RequestMethod.GET)
public Integer count() {
GET /api/v1/usuarios/count
return usuarioService.count()}
…
26
Servicios REST: ¿cómo consumirlos y testearlos?
• Con cualquier cliente HTTP (mas parser JSON o XML). Ej:
○ Bibliotecas (Ej.: Apache HTTP Client para Java)
○ Extensión de navegadores, como Postman client
• Los proveedores de servicios generalmente
ofrecen bibliotecas (wrappers o SDKs) para
consumir fácilmente sus servicios desde
distintos lenguajes y plataformas
(Java, Android, iOS, .NET, Javascript, etc)
27
Arquitectura por capas
●
Persistencia
○
○
○
●
Servicio
○
○
●
Services: operaciones listadas por el servicio
DAOs (Data Access Objects)/repository: interfaz a la capa de persistencia
Seguridad
○
●
Models: el objeto a nivel BD
Dtos (Data Transfer Object): objeto a nivel lenguaje
Mapper: conversión de un de un modelo a un Dto
Config y security: configuraciones del portal y administración de tokens de autenticación. Uso
de roles y permisos.
Controladores
○
Lleva a cabo la manipulación de todo, desde la invocación hasta preparar la respuesta. Aquí es
donde se publican los servicios que provee esta aplicación.
Arquitectura por tiers
– a nivel diseño
Inyección de dependencias (IoD)
• En la inyección de dependencias ‘alguien’ externo se encarga de las
dependencias que las clases necesitan
Framework Spring
• Es una infraestructura para la creación de aplicaciones Web en Java
(Kotlin, y Groovy), con integración con un gran abanico de tecnologías
• Distintos tipos de accesos a datos
• Incorpora el mecanismo de Inyección de Dependencias
• Spring Boot apunta a simplificar la creación
y (auto-)configuración de una aplicación
sobre Spring
• Integración de todo
en un único contenedor
Framework Spring
• La configuración
(en Spring Boot)
se realiza
mediante starters
Inversión de control (IoC)
• Spring maneja el
concepto de IoC,
ocupándose de mantener
en su ‘contexto’ todas
las instancias de la aplicación y
de inyectarle esa instancia
a quien la necesite
• Spring llama a estas instancias beans
• Los bean son las instancias de las clases que están disponibles para
ser reutilizados y son gestionados dentro del contenedor de Spring
Inversión de control (IoC)
• IoC es el trabajo
que realiza Spring
buscando estas
dependencias entre los objetos y
realizando el ‘set’ estos beans
en quien los requiera
• Spring sabe qué dependencias existen entre las instancias y se
encarga de satisfacerlas
• Busca en su contenedor de beans la instancia adecuada y se la
agrega al objeto cumpliendo así con la inyección de dependencias
Ventajas de IoD
• Mayor cohesión
• Cada clase debe tener una única responsabilidad, debe ser bien
específica en dicha responsabilidad y hacerla bien
• Menor acoplamiento
• Los cambios en una clase no deberían impactar en otra
Sirven como Pilares para
el desarrollo de Microservicios
Spring: Inyección de dependencias y anotaciones
●
●
●
●
@SpringBootApplication: es el disparador para que se ejecute la aplicación.
○
@Configuration: indica que en la clase se encuentra la configuración del proyecto.
○
@EnableAutoConfiguration: indica que se aplicará configuración automática a partir del starter que
se configuró.
○
@ComponentScan: ayuda a la localización de elementos etiquetados con otras anotaciones.
@RestController: esta sustituye a @Controller + @ResponseBody.
○
@Controller: con esta anotación Spring detecta a la clase.
○
@ResponseBody: con ello definimos lo que será el cuerpo de la respuesta.
@CheckPermissions: se utiliza para definir los permisos que se necesitará para ejecutar dicho servicio.
@RequestMapping: especificamos la ruta desde la que escuchará el servicio, y qué método le
corresponde.
●
●
●
@AutoWired: a través de esta Spring realiza la inyección de dependencias y no es necesario instanciarla.
@PathVariable: sirve para indicar con qué variable de la url se relaciona el parámetro sobre el que se esté
usando la anotación.
…
Ejemplo simplificado
• Mostrar las distintas capas
• Pero omitir (por ahora) la configuración del “contexto” de la aplicación
Ejemplo: Entity
• Definición del objeto en la BD
Ejemplo: Repository
• Operaciones sobre la capa de persistencia
Ejemplo: Servicio
• En la capa de servicio se listan las operaciones que se pueden
realizar sobre la capa de persistencia y que serán accesibles por el
controlador
@Autowired: anotación que
permite inyectar unas
dependencias con
otras dentro de Spring
Ejemplo: Controller
• Declara el acceso a todos los
servicios que se desea exponer
dentro
del mismo
dominio
• Se debe
modificar el
controller para
poder utilizar la
capa de servicio
Instalación
https://spring.io/tools
Testing REST: JUnit + HTTP Client
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
<version>4.1.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>1.8</version>
<scope>test</scope>
</dependency>
43
Testing REST: Apache HTTP Client
import org.apache.http.*;
public class Test {
public final HttpClient client = HttpClientBuilder.create().build();
@Test
public void testGetPerro() throws ClientProtocolException, IOException {
String url = BASE_URL + "/perros/1";
HttpGet request = new HttpGet(url);
HttpResponse response = client.execute(request);
System.out.println("Response Code : " + response.getStatusLine().getStatusCode());
String resultContent = getResultContent(response);
System.out.println("Response Content : " + resultContent);
}
44
Testing REST: Jersey Client
import org.glassfish.jersey.api.client.*;
public class Test {
public Client client = Client.create();
@Test
public void testGetPerro() throws ClientProtocolException, IOException {
String url = BASE_URL + "/perros/1";
WebResource webResource = client.resource(url);
ClientResponse response =
webResource.accept("application/json").get(ClientResponse.class);
System.out.println("Response Code : " + response.getStatus());
System.out.println("Response Content : " + response.getEntity(String.class));
}
45
Preguntas?
46
0
You can add this document to your study collection(s)
Sign in Available only to authorized usersYou can add this document to your saved list
Sign in Available only to authorized users(For complaints, use another form )