A lo largo de las entradas anteriores hemos analizado el modelo de joint point de AspectJ y la manera de definir las reglas que permitan seleccionar aquellos joint points de nuestro interés.
Durante esta entrada analizaremos el modo en el que se puede alterar el comportamiento de un sistema en los joint points seleccionados mediante la definición de los pointcuts.
Las reglas de tejido están compuestas de dos partes:
- advice: qué deseamos hacer.
- pointcuts: dónde aplicamos el advice anterior.
AspectJ soporta el crosscutting dinámico mediante el concepto de advices, construcciones similares a los métodos gracias a los cuales se permiten definir las acciones a ejecutar en los joint points seleccionados por un pointcut.
Categorías de advices
Dependiendo de las funcionalidades que se estén implementando será necesario llevar a cabo la lógica en un determinado lugar del flujo de ejecución original; así por ejemplo, si se está construyendo la seguridad de un sistema, el código tendrá que verificar dicha seguridad antes de la ejecución del joint point. En un sistema de cachés, la nueva funcionalidad tendría que ejecutarse alrededor del joint point original, intentando recuperar el valor de la caché, y en caso de que no exista, ejecutar el código real y añadirlo a la misma para futuras invocaciones. AspectJ ofrece tres categorías de advices que satisfacen los escenarios anteriores (y alguno más):
- Before Advice: se ejecutan anteriormente a la ejecución del joint point
- After Advice: se ejecutan posteriormente a la ejecución del joint point. Existen tres variantes diferentes
- After finally: se ejecuta tras la ejecución del join point independientemente del resultado de la misma.
- After returning: se ejecuta tras la ejecución del joint point siempre y cuando ésta última haya finalizado correctamente, es decir, sin lanzar ninguna excepción.
- After throwing: se ejecuta tras la ejecución fallida de un joint point, es decir, después de que dicho joint point dispare una excepción.
- Around Advice: rodean la ejecución del joint point.
Sintaxis de los advices
Aunque la sintaxis varía ligeramente dependiendo del tipo de advice que se esté escribiendo, se podría dividir su estructura general en tres partes claramente diferenciadas:
- Declaración del advice. En esta parte de la declaración se especifica el momento de ejecución del advice, es decir, si se ejecutará antes, después o alrededor de los joint points.
- Definición de los pointcuts. Se especifican los pointcuts sobre los que se desea actuar.
- Cuerpo del advice. Definición del código a ejecutar una vez se haya alcanzado el joint point indicado.
Veamos, por partes, un ejemplo sencillo de definición de un advice:
- En primer lugar se define un sencillo pointcut :
pointcut secureOperation(User user): call( * User.*(..)) && target(user)
- En el pointcut anterior estamos capturando todas las llamadas a cualquier método de la clase User, y, adicionalmente estamos recogiendo el objeto que actúa como target de la llamada. A continuación veremos un around advice para ilustrar la sintaxis:
Object around(User user):secureOperation(user){
System.out.println("Securing operation on user "
+ user.toString());
Object retValue = proceed(user);
System.out.println("Finished secured operation on user "
+ user.toString());
return retValue;
}
- En la definición anterior se puede ver la estructura de la declaración de un advice descrita anteriormente:
- La parte que precede a los dos puntos indica el momento de ejecución del advice (after,before,around). En este caso, se ejecutará alrededor del joint point seleccionado.
- La parte que sigue a los dos puntos representa el pointcut, es decir, la definición de los criterios que determinan cuándo se ejecutará el advice.
- La última parte representa el cuerpo del advice, es decir, el código que se ejecutará cuando alguno de los joint point definidos por el pointcut sea alcanzado.
Advices y métodos
Al igual que los métodos de una clase, los advices se utilizan para definir comportamiento. La sintaxis de éstos últimos es similar a la de los métodos aunque existen algunas diferencias dado que los advices son aplicados de manera automática, sin la necesidad de realizar explícitamente la invocación del mismo.
A continuación se analizan las similitudes entre ambos en tres categorías diferentes: declaración, cuerpo y comportamiento. La declaración de un advice es similar a la signatura de un método tradicional en que:
- Opcionalmente puede asignarse un nombre al advice mediante el uso de la anotación @AdviceName.
- Recibe argumentos a través del contexto del joint point, que posteriormente podrán ser utilizados en el cuerpo para implementar la lógica necesaria.
- Puede declarar el lanzamiento de una excepción.
- El cuerpo de los advices también es muy parecido al de los métodos puesto que:
- El código del cuerpo del advice sigue las mismas reglas de acceso a miembros de otros tipos y/o aspectos.
- Se puede referenciar a la propia instancia del aspecto mediante el uso de this.
- Los advices de tipo around pueden retornar un valor.
- Los advices deben declarar las excepciones que sean checked que la implementación podría disparar.
- En la categoría relativa al comportamiento, los advices :
- No pueden declarar el disparo de una excepción que no está declarada en TODOS los joint points sobre los que actúa.
- Pueden omitir algunas de las excepciones de tipo checked que han sido declaradas por alguno de los joint point sobre los que actúa.
- Pueden declarar el disparo de excepciones más específicas (de tipo checked) que las definidas por los joint point sobre los que está actuando.
- Pueden lanzar cualquier tipo de excepción de tipo runtime.
En comparación con los métodos, los advices presentan las siguientes diferencias:
- La declaración de un nombre es opcional.
- No pueden ser invocados directamente.
- No presentan especificadores de acceso (relacionado con la característica de que no pueden ser invocados directamente).
- No presentan un tipo de retorno en los advices de tipo before y after.
- Tienen acceso a unas cuantas variables dentro del propio aspecto: thisJointPoint, thisJointPointStaticPart, thisEnclosingJointPointStaticPart.
- Se puede utilizar la palabra reservada proceed en los advices de tipo around para ejecutar el joint point sobre el cual se está realizando el advice.
La siguiente entrada realizará un análisis más detallado de los advices y cómo se puede acceder a los contextos del joint point.
Hasta pronto!!