Spring framework 5 : AOP After throwing Advice


Como vimos en el post pasado https://devs4j.com/2019/02/28/spring-framework-5-aop-conceptos-basicos/ existen diferentes tipos de advices, en este post nos enfocaremos en After throwing Advice.

Para poder seguir estos ejemplos es necesario crear un proyecto spring boot simple.

Creación de un servicio de spring

El primer paso para entender como funcionan los advices será crear un servicio de spring, este objeto será nuestro Target object.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

/**
 * @author raidentrance
 *
 */
@Service
public class HelloWorldService {

	private static final Logger log = LoggerFactory.getLogger(HelloWorldService.class);

	public void print() {
		log.info("Hello world");
		throw new IllegalStateException();
	}

}

Como vemos nuestro servicio es solo una clase llamada HelloWorldService con un método llamado print().

After throwing Advice

En este ejemplo interceptaremos las peticiones a la clase HelloWorldService en su método print utilizando un After Throwing Advice, veamos el siguiente ejemplo:

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * @author raidentrance
 *
 */
@Aspect
@Component
public class AfterThrowingAdviceExample {
	
	private static final Logger log = LoggerFactory.getLogger(AfterThrowingAdviceExample.class);

	@AfterThrowing("execution(* com.devs4j.service.HelloWorldService.*(..))")
	public void logAfterThrowing(JoinPoint joinPoint) {
		log.info("After throwing example");
	}
}

Del código anterior podemos analizar los siguientes puntos:

  • La clase esta anotada con @Component y @Aspect esto permite a spring identificarlo como un bean y como un aspecto.
  • La anotación @AfterThrowing nos permite utilizar un After throwing advice.
  • Los advices reciben como parámetro un Pointcut el cual define los objetos que serán afectados por el Advice (Explicaremos Pointcut expression language en otro post).
  • El método recibe como parámetro un objeto que implementa la interfaz JoinPoint, esto nos permite acceder a información del JoinPoint que se interceptó.
  • Lo único que hace nuestro aspecto es imprimir el mensaje After throwing example
  • Los Advices After throwing se ejecutan después de que se ejecutó el método interceptado siempre y cuando haya habido una excepción.

Una vez que tenemos listo nuestro aspecto el siguiente paso será probarlo, para esto crearemos la siguiente clase:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

import com.devs4j.service.HelloWorldService;

@SpringBootApplication
public class Devs4jSpringAopApplication {

	public static void main(String[] args) {
		ConfigurableApplicationContext applicationContext = SpringApplication.run(Devs4jSpringAopApplication.class,
				args);
		HelloWorldService helloWorldService = applicationContext.getBean(HelloWorldService.class);
		helloWorldService.print();
	}

}

Del código anterior podemos analizar los siguientes puntos:

  • Obtenemos un bean del tipo HelloWorldService
  • Ejecutamos el método print()

Salida:

2019-03-01 12:53:58.076  INFO 76486 --- [           main] com.devs4j.service.HelloWorldService     : Hello world
2019-03-01 12:53:58.078  INFO 76486 --- [           main] c.devs4j.aop.AfterThrowingAdviceExample  : After throwing example
Exception in thread "main" java.lang.IllegalStateException
	at com.devs4j.service.HelloWorldService.print(HelloWorldService.java:21)
	at com.devs4j.service.HelloWorldService$$FastClassBySpringCGLIB$$c594d12f.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:62)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
	at com.devs4j.service.HelloWorldService$$EnhancerBySpringCGLIB$$28652767.print(<generated>)
	at com.devs4j.Devs4jSpringAopApplication.main(Devs4jSpringAopApplication.java:16)

Como vemos se imprimió el mensaje After throwing example después de Hello world, esto nos indica que el aspecto que utiliza after throwing advice se ejecuta después del método print debido a que este arroja una IllegalStateException.

Para estar al pendiente sobre nuestro contenido nuevo síguenos en nuestras redes sociales https://www.facebook.com/devs4j/ y https://twitter.com/devs4j.

Autor: Alejandro Agapito Bautista
Twitter: @raidentrance
Contacto:raidentrance@gmail.com

Spring framework 5 : AOP Conceptos básicos


AOP (Aspect oriented programming) es un paradigma de programación al igual que la POO (Programación orientada a objetos), en la POO el punto principal de la programación es un objeto mientras que en AOP es un aspecto.

Los aspectos nos ayudan a solucionar problemas llamados crosscutting concerns, para poder adentrarnos a esto primero debemos entender algunos conceptos básicos de AOP:

  • Aspect : Un aspecto es una preocupación o funcionalidad que se aplica a multiples clases, el logging es un buen ejemplo.
  • Join point : Un punto durante la ejecución de un programa como la ejecución de un método o el manejo de una excepción, en Spring Aop siempre será la ejecución de un método.
  • Advice : Será la acción a tomar en un join point específico, existen diferentes tipos de advice “around”, “before” y “after”, se pueden considerar como “interceptores” de nuestros join points.
  • Pointcut : Un predicado que junta un conjunto de join points, para definir este predicado se utiliza AspectJ pointcut expression language.
  • Target object : Un objeto advised por uno o más aspectos, como Spring Aop utiliza proxys este siempre será un objeto proxied.
  • Aop proxy : Un objeto creado por el framework Aop para dar el soporte Aop, en Spring Aop se utiliza proxies dinámicos a través de CGLIB.
  • Weaving : Es el enlace entre los aspectos y los objetos, este se puede hacer de diferentes formas, Spring Aop lo hace en tiempo de ejecución.

Tipos de Advices

Como se menciono anteriormente existen diferentes tipos de advices:

  • Before advice : Este advice se ejecuta antes del join point, no tiene la habilidad de detener la ejecución a menos de que arroje una excepción.
  • After returning : Este advice se ejecuta después del join point, no se ejecuta si hay una excepción.
  • After throwing : Este advise se ejecuta si el método termina por una excepción.
  • After finally : Este advise se ejecuta si el método termina su ejecución de forma normal o por una excepción.
  • Around advice : Este advise rodea la ejecución de un método, puede ejecutar su comportamiento antes, después o incluso si se produce una excepción. También es responsable de determinar si quiere o no proceder con la invocación del método.

Around advice es el advice más poderoso pero es el más general, por esto se recomienda utilizar el más especifico para resolver el problema que necesitamos.

Usos prácticos

Algunos usos prácticos para el uso de Spring Aop son :

  • Logging
  • Seguridad
  • Administración de transacciones
  • Monitoreo de performance
  • Caching
  • Manejo de errores

Para estar al pendiente sobre nuestro contenido nuevo síguenos en nuestras redes sociales https://www.facebook.com/devs4j/ y https://twitter.com/devs4j.

Autor: Alejandro Agapito Bautista
Twitter: @raidentrance
Contacto:raidentrance@gmail.com