Jakarta Annotations en Quarkus: Gestión del Ciclo de Vida y Anotaciones Personalizadas
Introducción
Jakarta Annotations proporciona anotaciones estándar para gestionar el ciclo de vida de componentes y crear anotaciones personalizadas. En Quarkus, estas anotaciones están completamente soportadas y funcionan de forma integrada con CDI.
¿Qué son las Anotaciones?
Las anotaciones en Java son metadatos que se pueden agregar a clases, métodos, campos y otros elementos del código. Jakarta EE define varias anotaciones estándar para gestionar el ciclo de vida y comportamiento de los componentes.
Anotaciones Estándar de Jakarta
@PostConstruct
Se ejecuta después de que el bean ha sido construido e inyectado:
@ApplicationScoped
public class HeroService {
@PostConstruct
public void init() {
// Se ejecuta después de la construcción
// Útil para inicialización
logger.info("HeroService initialized");
}
}
@PreDestroy
Se ejecuta antes de que el bean sea destruido:
@ApplicationScoped
public class HeroService {
@PreDestroy
public void cleanup() {
// Se ejecuta antes de la destrucción
// Útil para liberar recursos
logger.info("HeroService cleaning up");
}
}
@Resource
Inyecta recursos del contenedor:
@ApplicationScoped
public class HeroService {
@Resource
private Logger logger;
@Resource(name = "jdbc/heroesDB")
private DataSource dataSource;
}
@Generated
Marca código generado automáticamente:
@Generated(value = "code-generator", date = "2024-01-01")
public class GeneratedHero {
// Código generado
}
Anotaciones Personalizadas
Crear una Anotación Personalizada
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface HeroPower {
int minLevel() default 1;
String description() default "";
}
Usar la Anotación
@HeroPower(minLevel = 80, description = "Héroe poderoso")
@Loggable(level = "INFO")
public void activateHero(String name) {
// Método marcado con anotaciones personalizadas
}
Anotación para Logging
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Loggable {
String level() default "DEBUG";
boolean includeArgs() default true;
boolean includeResult() default false;
}
Anotación para Validación
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PowerLevelValidator.class)
public @interface PowerLevel {
String message() default "Nivel de poder inválido";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
int min() default 1;
int max() default 100;
}
Procesamiento de Anotaciones
Leer Anotaciones en Runtime
public void processAnnotations(Object obj) {
Class<?> clazz = obj.getClass();
// Leer anotaciones de clase
if (clazz.isAnnotationPresent(HeroPower.class)) {
HeroPower annotation = clazz.getAnnotation(HeroPower.class);
int minLevel = annotation.minLevel();
String description = annotation.description();
}
// Leer anotaciones de métodos
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(HeroPower.class)) {
HeroPower annotation = method.getAnnotation(HeroPower.class);
// Procesar método
}
}
}
Ejemplo Completo: Servicio con Anotaciones
@ApplicationScoped
public class HeroService {
private List<Hero> heroes = new ArrayList<>();
@PostConstruct
public void init() {
// Inicializar datos después de la construcción
heroes.add(new Hero("Superman", "Super fuerza", 95));
heroes.add(new Hero("Batman", "Inteligencia", 85));
logger.info("HeroService initialized with " + heroes.size() + " heroes");
}
@PreDestroy
public void cleanup() {
// Limpiar recursos antes de destruir
heroes.clear();
logger.info("HeroService cleaned up");
}
@HeroPower(minLevel = 80)
@Loggable(level = "INFO")
public Hero getPowerfulHero(String name) {
return heroes.stream()
.filter(h -> h.getName().equals(name))
.filter(h -> h.getPowerLevel() >= 80)
.findFirst()
.orElse(null);
}
}
Ciclo de Vida de Beans con Anotaciones
El ciclo de vida de un bean en Quarkus con CDI:
Construcción: El bean se instancia
Inyección: Las dependencias se inyectan
@PostConstruct: Se ejecuta el método marcado
Uso: El bean está listo para usar
@PreDestroy: Se ejecuta antes de destruir (al cerrar la aplicación)
Anotaciones y CDI
Las anotaciones funcionan perfectamente con CDI:
@ApplicationScoped
@HeroPower(minLevel = 70)
public class PowerAnalysisService {
@Inject
HeroService heroService;
@PostConstruct
public void initialize() {
// Inicialización después de la construcción e inyección
}
}
Ejemplo Completo
Nuestro demo muestra:
@PostConstruct y @PreDestroy para ciclo de vida
@Resource para inyección de recursos
@Generated para código generado
Anotaciones personalizadas (@HeroPower, @Loggable, @PowerLevel)
Procesamiento de anotaciones en runtime
Ventajas en Quarkus
Integración CDI: Funciona perfectamente con CDI
Ciclo de Vida: Gestión automática del ciclo de vida
Flexibilidad: Fácil crear anotaciones personalizadas
Metadatos: Las anotaciones proporcionan metadatos útiles
Casos de Uso
Inicialización de Servicios
@PostConstruct
public void init() {
// Cargar configuración
// Inicializar conexiones
// Preparar datos en memoria
}
Limpieza de Recursos
@PreDestroy
public void cleanup() {
// Cerrar conexiones
// Liberar recursos
// Guardar estado
}
Anotaciones de Dominio
@HeroPower(minLevel = 90)
public class LegendaryHeroService {
// Servicio para héroes legendarios
}
Conclusión
Las anotaciones en Quarkus proporcionan una forma poderosa de gestionar el ciclo de vida y agregar metadatos al código. Las anotaciones estándar como @PostConstruct y @PreDestroy son esenciales, mientras que las anotaciones personalizadas permiten crear APIs específicas del dominio.




