Cuando trabajamos con Spring Boot, uno de los mayores beneficios es la flexibilidad y el poder de sus anotaciones. Estas anotaciones permiten simplificar el desarrollo de aplicaciones al gestionar la inyección de dependencias, la configuración automática y muchos otros aspectos del ciclo de vida de la aplicación. Pero, ¿qué sucede cuando las anotaciones predeterminadas no se ajustan exactamente a nuestras necesidades? Aquí es donde entran en juego las anotaciones personalizadas. 💡
En Java, una anotación es una forma de agregar metadatos a nuestro código fuente. Spring Boot aprovecha las anotaciones para automatizar muchas tareas comunes. Una anotación personalizada es simplemente una anotación creada por nosotros mismos para cumplir una función específica en nuestra aplicación.
Estas anotaciones se pueden utilizar para:
👉 Un ejemplo común sería una anotación que verifique permisos antes de ejecutar un método.
Primero, veamos un ejemplo simple de una anotación personalizada que no hace nada especial, solo es un marcador.
Creamos un archivo Java en nuestro proyecto llamado @MiAnotacion.java
:
package com.ejemplo.anotaciones;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MiAnotacion {
String valor() default "Hola desde la anotación personalizada";
}
Ahora que tenemos nuestra anotación, probémosla en un controlador de Spring Boot:
package com.ejemplo.controlador;
import com.ejemplo.anotaciones.MiAnotacion;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MiControlador {
@MiAnotacion(valor = "Este es un mensaje personalizado")
@GetMapping("/saludo")
public String saludo() {
return "¡Hola Mundo!";
}
}
1. Inicia tu aplicación Spring Boot.
2. Ve a http://localhost:8080/saludo
y verás "¡Hola Mundo!" como respuesta.
Aunque la anotación no hace nada aún, ¡ya estamos listos para agregar lógica! 😉
Vamos a darle vida a nuestra anotación usando AOP de Spring, lo que nos permitirá interceptar métodos anotados y realizar acciones antes, después o alrededor de su ejecución.
Primero, asegúrate de tener la dependencia de AOP en tu pom.xml
:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
Creamos una clase llamada MiAspecto.java
para manejar la anotación:
package com.ejemplo.aspecto;
import com.ejemplo.anotaciones.MiAnotacion;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class MiAspecto {
@Before("@annotation(miAnotacion)")
public void antesDelMetodo(JoinPoint joinPoint, MiAnotacion miAnotacion) {
System.out.println("Ejecutando antes del método: " + joinPoint.getSignature());
System.out.println("Valor de la anotación: " + miAnotacion.valor());
}
}
antesDelMetodo
se ejecutará antes de cualquier método anotado con @MiAnotacion
.
Reinicia tu aplicación y accede nuevamente a http://localhost:8080/saludo
.
En la consola deberías ver algo como:
Ejecutando antes del método: String com.ejemplo.controlador.MiControlador.saludo()
Valor de la anotación: Este es un mensaje personalizado
¡Funciona! Ahora tenemos una anotación personalizada que ejecuta lógica antes del método anotado. 🎉
Imaginemos que queremos validar si un usuario tiene permisos antes de ejecutar un método.
package com.ejemplo.seguridad;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequierePermiso {
String valor();
}
package com.ejemplo.aspecto;
import com.ejemplo.seguridad.RequierePermiso;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class SeguridadAspecto {
@Before("@annotation(requierePermiso)")
public void validarPermiso(JoinPoint joinPoint, RequierePermiso requierePermiso) {
String permisoRequerido = requierePermiso.valor();
// Simulación de validación
if (!"ADMIN".equals(permisoRequerido)) {
throw new SecurityException("Acceso denegado");
}
System.out.println("Permiso validado correctamente");
}
}
package com.ejemplo.controlador;
import com.ejemplo.seguridad.RequierePermiso;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SeguridadControlador {
@RequierePermiso(valor = "ADMIN")
@GetMapping("/admin")
public String accesoAdmin() {
return "Acceso permitido";
}
}
Ahora, si accedes a http://localhost:8080/admin
, obtendrás:
Las anotaciones personalizadas en Spring Boot son una poderosa herramienta que facilita la implementación de comportamientos repetitivos y permite separar la lógica de negocio de la lógica transversal. Con AOP podemos aplicar reglas de validación, manejo de errores y cualquier otra lógica que necesitemos.
¡Espero que este artículo te haya sido útil y que te animes a usar anotaciones personalizadas en tus proyectos Spring Boot! 🚀
Jorge García
Fullstack developer