Preparado por Miguel Angel Madrigal 🙂
Spring simplifica el trabajo con AOP a través del framework AOP AspectJ.
A continuación se describe un pequeño ejemplo para ilustrar su uso en un caso típico. En el ejemplo veremos cómo hacer que un método de negocio decorado con una anotación @Trazable genere una traza informando de la duración de la invocación del método.
- Creación de la anotación
En primer lugar definiremos en nuestro proyecto una anotación sencilla, que usaremos posteriormente para indicar que un determinado método va a ser trazable. Es importante que definamos la anotación de modo que esté disponible en tiempo de ejecución:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Trazable {
}
Para el caso de nuestro ejemplo no definiremos ningún atributo en la anotación, aunque en un caso general es perfectamente posible.
Observamos que nuestra anotación está, a su vez, decorada con la anotación @Retention, que nos permite establecer la política de retención. El valor indicado RetentionPolicy.RUNTIME indica que la metainformación que representa nuestra anotación estará disponible en tiempo de ejecución.
La anotación @Target sirve para indicar qué tipo de estructuras van a poder decorarse con nuestra anotación. El valor ElementType.METHOD indica que nuestra anotación únicamente puede aplicarse a métodos.
- Creación de un bean de negocio que utilice la anotación
A continuación, y para que resulte más fácil comprender los conceptos, crearemos un bean de negocio con un método decorado con la anotación @Trazable.
@Component
public class BeanTrazable {
@Trazable
public void metodoTrazable() {
try {
Thread.sleep(1000);
} catch ( InterruptedException e ) {}
}
}
Observamos que hemos decorado la clase con @Component para indicar que esta clase deberá ser desplegada en Spring como un bean. La clase dispone de un método metodoTrazable, decorado con nuestra anotación @Trazable. El método simplemente introduce una espera de un segundo.
- Creación del aspecto
A continuación vamos a crear un aspecto que controle la invocación de los métodos que anotemos como @Trazable. Para ello creamos una clase AspectoTrazable, y la anotamos como @Aspect.
@Aspect
public class AspectoTrazable {
private static final Log log = LogFactory.getLog(AspectoTrazable.class);
@Around("execution(* *(..)) && @annotation(trazable)")
public Object trazar(ProceedingJoinPoint pjp, Trazable trazable) throws Throwable {
long instanteInicial = System.currentTimeMillis();
Object resultado = null;
Throwable throwable = null;
try {
resultado = pjp.proceed();
} catch ( Throwable t ) {
throwable = t;
}
long instanteFinal = System.currentTimeMillis();
log.info("Invocacion de metodo: " + pjp.getSignature() + ", duracion: " + (instanteFinal – instanteInicial));
if ( throwable == null ) return resultado;
throw throwable;
}
}
Observamos que se define un método trazar , que está decorado con la anotación @Around. Esta anotación indica dos cosas:
- Mediante el valor "execution(* *(..)) && @annotation(trazable)" que contiene, estamos indicando que nuestro aspecto aplicará en la ejecución de cualquier clase y método que contenga una anotación cuyo tipo de datos es el del parámetro de nombre ‘trazable’ en nuestro método. En este caso, este parámetro trazable será del tipo Trazable, la anotación que definimos anteriormente.
- Que la lógica que vamos a definir en nuestro método trazar queremos que aplique antes y después de la ejecución de los métodos decorados con @Trazable.
El método dispone de dos argumentos. El primero de ellos es un ProceedingJoinPoint, que representa el punto en nuestro código en el que se introducirán las acciones llevadas a cabo por el aspecto que estamos definiendo, esto es, todos y cada uno de los métodos decorados con @Trazable que se definan. En el caso de nuestro ejemplo sólo hay un único caso, de modo que representará al método metodoTrazable de la clase BeanTrazable.
El segundo de ellos es la instancia de Trazable que decore al método trazable concreto que se esté ejecutando cuando aplique nuestro aspecto. En el caso de nuestro ejemplo, sería la anotación del método metodoTrazable de la clase BeanTrazable. Si la anotación tuviera atributos, veríamos aquí sus valores concretos para el método metodoTrazable.
La implementación del método trazar sigue los siguientes tres pasos:
- En primer lugar, tomamos una medida del instante inicial en que se produce la invocación.
- A continuación usamos el objeto ProceedingJoinPoint que recibimos como argumento para propagar la invocación. Cuando hacemos esto, lo que está sucediendo en realidad es que comenzará la ejecución del método decorado con @Trazable. En el caso concreto de nuestro ejemplo, se comenzaría a ejecutar el método metodoTrazable de la clase BeanTrazable, con lo que comenzaría la espera de un segundo. Guardamos el resultado de la invocación y el posible Throwable que pueda lanzarse en la ejecución del método decorado con @Trazable.
- Después de la invocación del método sobre el que aplica el aspecto, éste recupera el control para tomar una medida del instante final, y a continuación generar una traza informando del nombre del método decorado con @Trazable, así como de la duración de la invocación.
- Finalmente, se retorna el resultado o excepción que guardamos previamente.
- Creación de un test para verlo en funcionamiento
A continuación vamos a crear un test para ver en funcionamiento el aspecto que acabamos de confeccionar:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:/META-INF/spring/applicationContext.xml")
public class TestAspectoTrazable {
@Autowired
private BeanTrazable beanTrazable;
@Test
public void test() {
beanTrazable.metodoTrazable();
}
}
Observamos que el test recibe una instancia de nuestro BeanTrazable, y a continuación define un método test que simplemente invoca el método metodoTrazable. Si ejecutamos el test y observamos las trazas que genera, veremos cómo el aspecto ha escrito la traza con la duración de la invocación:
16/11/2011 12:07:57.754 INFO main [AspectoTrazable.metodoTrazable_aroundBody1$advice:30] Invocacion de metodo: void com.bbva.arq.front.spring.demo.aspectos.BeanTrazable.metodoTrazable(), duracion: 1000

Deja un comentario