Spring Boot

SpringBoot

Tutorial SpringBoot: Servicios en Spring

Spring Boot servicios: creación y uso. Domina la creación y uso de servicios en Spring Boot con ejemplos prácticos y detallados.

Introducción

Los servicios en Spring desempeñan un papel fundamental en la arquitectura de aplicaciones, promoviendo una clara separación de responsabilidades y facilitando la reutilización de la lógica de negocio. 

Al abstraer la lógica de negocio en servicios, Spring permite desarrollar aplicaciones más organizadas, modulares y fáciles de mantener. 

Esta lección se enfoca en comprender la importancia de los servicios en Spring, cómo declararlos, gestionar sus dependencias, manejar transacciones y crear servicios REST.

Declarar un servicio

Los servicios en Spring se definen típicamente en clases Java anotadas con @Service. Esta anotación es una especialización de @Component, indicando que la clase anotada ofrece funcionalidad de servicio (lógica de negocio o accesos a base de datos) dentro de la aplicación.

Crear un servicio básico

Para declarar un servicio en Spring, se sigue el siguiente patrón:

import org.springframework.stereotype.Service;

@Service
public class CalculadoraService {

    public double calcularTotal(double cantidad, double precio) {
        return cantidad * precio;
    }
}

Este ejemplo muestra un servicio simple CalculadoraService que incluye un método para calcular el total de un pedido. La anotación @Service sobre la clase indica a Spring que esta clase es un candidato para la detección automática de componentes y que debe ser gestionada como un bean de Spring.

Diferencias entre anotaciones de estereotipo

Es crucial distinguir entre las anotaciones de estereotipo en Spring:

  • @Component: La anotación genérica para cualquier componente gestionado por Spring.
  • @Service: Se utiliza específicamente para marcar clases que realizan servicios, como operaciones de lógica de negocio.
  • @Repository: Especializada para marcar clases que acceden a la capa de persistencia, facilitando operaciones de base de datos.
  • @Controller (o @RestController para servicios REST): Utilizada para marcar controladores en aplicaciones web o servicios REST.

La elección de la anotación adecuada para cada componente mejora la claridad del código y ayuda a Spring a aplicar comportamientos específicos, como el manejo de excepciones de base de datos en los repositorios.

Este enfoque en la declaración y organización de servicios en Spring sienta las bases para construir aplicaciones robustas y mantenibles, alineándose con los principios de diseño de software y facilitando la gestión de la complejidad en aplicaciones empresariales.

Inyectar dependencias

La inyección de dependencias es un patrón de diseño clave en el desarrollo de software que Spring facilita a través de su contenedor de inversión de control (IoC). Permite a los desarrolladores mantener sus clases limpias de la lógica de creación de objetos, promoviendo un acoplamiento débil, mayor modularidad y facilidad de pruebas.

Uso de @Autowired para inyectar dependencias

Spring proporciona la anotación @Autowired para automatizar la inyección de dependencias. 

Se puede aplicar sobre campos, métodos setter o constructores de una clase para indicar a Spring dónde y cómo inyectar los beans necesarios.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class PedidoService {

    private final CalculadoraService calculadoraService;

    @Autowired
    public PedidoService(CalculadoraService calculadoraService) {
        this.calculadoraService = calculadoraService;
    }

    public double calcularTotalPedido(double cantidad, double precio) {
        return calculadoraService.calcularTotal(cantidad, precio);
    }
}

En este ejemplo, PedidoService depende de CalculadoraService para realizar sus operaciones. Al marcar el constructor con @Autowired, Spring se encarga de buscar un bean de tipo CalculadoraService y lo inyecta automáticamente al crear una instancia de PedidoService.

En este ejemplo concreto podría hacerse sin utilizar la anotación @Autowired ya que solo hay un constructor.

Buenas prácticas en la inyección de dependencias

  • Preferir la inyección a través del constructor: Facilita la creación de instancias inmutables y mejora la testabilidad, ya que permite pasar dependencias mock o stub durante las pruebas.
  • Uso moderado de la inyección de campo: Aunque @Autowired puede aplicarse directamente sobre un campo, esta práctica puede dificultar las pruebas y el seguimiento de las dependencias, por lo que se recomienda su uso principalmente en configuraciones sencillas o prototipos rápidos.
  • Contexto de beans de Spring: Para que @Autowired funcione, tanto la clase dependiente como la dependencia deben ser gestionadas por el contenedor de Spring, típicamente anotadas con @Service, @Component, @Repository, o @Controller.

La inyección de dependencias juega un papel crucial en el desarrollo de aplicaciones Spring, permitiendo una mayor flexibilidad, mantenibilidad y facilitando el proceso de pruebas.

Gestión de transacciones en servicios

La gestión de transacciones es fundamental en aplicaciones empresariales, especialmente cuando se trabaja con operaciones de base de datos que necesitan ser ejecutadas de manera segura y consistente. Spring proporciona un poderoso soporte de abstracción para la gestión de transacciones que simplifica el trabajo con diferentes tecnologías de persistencia.

Uso de @Transactional

Spring ofrece la anotación @Transactional para declarar de forma declarativa el comportamiento transaccional en los métodos de servicio. Al anotar una clase o método con @Transactional, se asegura que el método se ejecute dentro de un contexto transaccional.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class PedidoService {

    private final PedidoRepository pedidoRepository;

    @Autowired
    public PedidoService(PedidoRepository pedidoRepository) {
        this.pedidoRepository = pedidoRepository;
    }

    @Transactional
    public Pedido crearPedido(Pedido pedido) {
        validarPedido(pedido);
        return pedidoRepository.save(pedido);
    }

    private void validarPedido(Pedido pedido) {
        // Lógica de validación del pedido
    }
}

En este ejemplo, el método crearPedido está marcado con @Transactional, lo que indica que la operación de guardar el pedido en la base de datos debe ser completada con éxito para que la transacción se confirme. 

Si ocurre una excepción durante el proceso, la transacción se revertirá automáticamente, evitando la persistencia de un estado inconsistente.

De esta forma es posible crear métodos transaccionales dentro de servicios.

En Spring Data JPA, los métodos heredados en los repositorios ya son transaccionales, por lo que no es necesario agregar @Transactional en los servicios a todos los métodos. Se utilizaría cuando:

  • Se interactúa directamente con EntityManager y se quiere trabajar con transacciones a nivel de JPA directamente
  • Cuando se crean métodos como delete dentro de un repositorio Spring Data JPA

Consideraciones Importantes en la Gestión de Transacciones

  • Propagación de transacciones: La anotación @Transactional permite especificar el comportamiento de propagación de la transacción, como REQUIRED, REQUIRES_NEW, entre otros, lo cual define cómo se manejan las transacciones en métodos anidados o llamadas sucesivas.
  • Aislamiento de transacciones: Se puede configurar el nivel de aislamiento de la transacción para prevenir problemas como condiciones de carrera, datos sucios, lecturas fantasmas, etc.
  • Manejo de excepciones: Spring convierte las excepciones específicas de la tecnología de persistencia usada (como JDBC, Hibernate) en su propia jerarquía de excepciones de tiempo de ejecución, simplificando el manejo de errores en la capa de servicios.

La gestión de transacciones en Spring no solo asegura la consistencia de los datos y la integridad de la base de datos, sino que también facilita el desarrollo de servicios robustos y confiables, permitiendo a los desarrolladores centrarse más en la lógica de negocio.

Testing de Servicios

La implementación y prueba de servicios en Spring son etapas cruciales para asegurar la calidad y el funcionamiento adecuado de las aplicaciones. Spring Boot, junto con Spring Framework, proporciona herramientas y anotaciones que facilitan la escritura de pruebas para servicios.

Implementación de un Servicio

La implementación efectiva de servicios en Spring involucra la creación de componentes bien definidos que se encargan de la lógica de negocio, la interacción con bases de datos mediante repositorios, y la exposición de funcionalidades a través de controladores REST.

import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class UsuarioService {

    private final UsuarioRepository usuarioRepository;

    public UsuarioService(UsuarioRepository usuarioRepository) {
        this.usuarioRepository = usuarioRepository;
    }

    public List<Usuario> listarUsuarios() {
        return usuarioRepository.findAll();
    }
}

Este servicio UsuarioService ofrece una operación para listar usuarios, interactuando con un repositorio para recuperar los datos.

Testing de Servicios

Spring Boot facilita el testing de componentes mediante anotaciones como @SpringBootTest para pruebas de integración y @DataJpaTest para pruebas relacionadas con JPA. Para pruebas unitarias de servicios, se puede utilizar @MockBean para simular dependencias.

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;

import static org.mockito.Mockito.verify;

@SpringBootTest
public class UsuarioServiceTest {

    @Autowired
    private UsuarioService usuarioService;

    @MockBean
    private UsuarioRepository usuarioRepository;

    @Test
    void listarUsuariosTest() {
        usuarioService.listarUsuarios();
        verify(usuarioRepository).findAll();
    }
}

Esta prueba verifica que el método listarUsuarios del servicio UsuarioService invoca el método findAll del repositorio UsuarioRepository.

Conclusión

A lo largo de esta lección, se ha explorado el desarrollo de servicios en Spring, desde su declaración y organización hasta la inyección de dependencias y la gestión de transacciones. Se han abordado también aspectos fundamentales para la creación de servicios REST utilizando Spring Boot, así como prácticas recomendadas para la implementación y el testing de estos servicios.

Esta comprensión integral no solo permite crear aplicaciones robustas y mantenibles, sino que también asegura que los desarrolladores puedan construir y probar sus servicios de manera eficiente, aprovechando las potentes características y facilidades que Spring y Spring Boot ofrecen para el desarrollo de aplicaciones empresariales modernas.

Certifícate en SpringBoot con CertiDevs PLUS

Ejercicios de esta lección Servicios en Spring

Evalúa tus conocimientos de esta lección Servicios en Spring con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Web y Test Starters

Spring Boot
Puzzle

Entidades JPA

Spring Boot
Test

Repositorios reactivos

Spring Boot
Test

Inserción de datos

Spring Boot
Test

Borrar datos de base de datos

Spring Boot
Test

Controladores Spring MVC

Spring Boot
Código

Backend API REST con Spring Boot

Spring Boot
Proyecto

Operadores Reactivos

Spring Boot
Puzzle

Controladores Spring REST

Spring Boot
Código

Uso de Spring con Thymeleaf

Spring Boot
Puzzle

Crear entidades JPA

Spring Boot
Código

Registro de usuarios

Spring Boot
Test

CRUD y JPA Repository

Spring Boot
Puzzle

Anotaciones y mapeo en JPA

Spring Boot
Puzzle

Integración con Vue

Spring Boot
Test

Consultas JPQL con @Query en Spring Data JPA

Spring Boot
Test

Open API y cómo agregarlo en Spring Boot

Spring Boot
Puzzle

Uso de Controladores REST

Spring Boot
Puzzle

API Specification

Spring Boot
Puzzle

Inyección de dependencias

Spring Boot
Test

Introducción a Spring Boot

Spring Boot
Test

Consultas JPQL con @Query en Spring Data JPA

Spring Boot
Puzzle

API Query By Example (QBE)

Spring Boot
Puzzle

Inyección de dependencias

Spring Boot
Código

Vista en Spring MVC con Thymeleaf

Spring Boot
Test

Servicios en Spring

Spring Boot
Código

Configuración de Vue

Spring Boot
Puzzle

Integración con Angular

Spring Boot
Test

API Query By Example (QBE)

Spring Boot
Test

API Specification

Spring Boot
Test

Controladores MVC

Spring Boot
Test

Métodos find en repositorios

Spring Boot
Test

Repositorios Spring Data

Spring Boot
Test

Inyección de dependencias

Spring Boot
Puzzle

Data JPA y Mail Starters

Spring Boot
Test

Configuración de Angular

Spring Boot
Puzzle

Controladores Spring REST

Spring Boot
Test

Configuración de Controladores MVC

Spring Boot
Puzzle

Asociaciones de entidades JPA

Spring Boot
Código

Actualizar datos de base de datos

Spring Boot
Test

Identificadores y relaciones JPA

Spring Boot
Puzzle

Verificar token JWT en peticiones

Spring Boot
Test

Login de usuarios

Spring Boot
Test

Integración con React

Spring Boot
Test

Configuración de React

Spring Boot
Puzzle

Asociaciones en JPA

Spring Boot
Test

Consultas JPQL

Spring Boot
Código

Todas las lecciones de SpringBoot

Accede a todas las lecciones de SpringBoot y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Introducción A Spring Boot

Spring Boot

Introducción Y Entorno

Spring Boot Starters

Spring Boot

Introducción Y Entorno

Inyección De Dependencias

Spring Boot

Introducción Y Entorno

Controladores Spring Mvc

Spring Boot

Spring Web

Vista En Spring Mvc Con Thymeleaf

Spring Boot

Spring Web

Controladores Spring Rest

Spring Boot

Spring Web

Open Api Y Cómo Agregarlo En Spring Boot

Spring Boot

Spring Web

Servicios En Spring

Spring Boot

Spring Web

Crear Entidades Jpa

Spring Boot

Persistencia Con Spring Data

Asociaciones De Entidades Jpa

Spring Boot

Persistencia Con Spring Data

Repositorios Spring Data

Spring Boot

Persistencia Con Spring Data

Métodos Find En Repositorios

Spring Boot

Persistencia Con Spring Data

Inserción De Datos

Spring Boot

Persistencia Con Spring Data

Actualizar Datos De Base De Datos

Spring Boot

Persistencia Con Spring Data

Borrar Datos De Base De Datos

Spring Boot

Persistencia Con Spring Data

Consultas Jpql Con @Query En Spring Data Jpa

Spring Boot

Persistencia Con Spring Data

Api Query By Example (Qbe)

Spring Boot

Persistencia Con Spring Data

Repositorios Reactivos

Spring Boot

Persistencia Con Spring Data

Api Specification

Spring Boot

Persistencia Con Spring Data

Integración Con React

Spring Boot

Integración Frontend

Integración Con Vue

Spring Boot

Integración Frontend

Integración Con Angular

Spring Boot

Integración Frontend

Registro De Usuarios

Spring Boot

Seguridad Con Spring Security

Login De Usuarios

Spring Boot

Seguridad Con Spring Security

Verificar Token Jwt En Peticiones

Spring Boot

Seguridad Con Spring Security

En esta lección

Objetivos de aprendizaje de esta lección

  1. Comprender el concepto de servicios en Spring y su importancia en la arquitectura de una aplicación.
  2. Aprender a declarar un servicio en Spring utilizando la anotación @Service.
  3. Entender cómo inyectar dependencias en los servicios con @Autowired.
  4. Conocer la gestión de transacciones en los servicios de Spring.
  5. Familiarizarse con la creación de servicios REST utilizando Spring Boot.
  6. Practicar la implementación y el testing de servicios en Spring.