Sunteți pe pagina 1din 6

Mi primer Programa Orientado a Aspectos

Lic. Fernando Asteasuain

Para iniciarnos en el mundo de la POA, qué mejor que hacerlo con el clásico programa
“Hola Mundo”. Empecemos entonces. Los requerimientos para nuestro sistema son:
• Que muestre por pantalla la expresión “¡Hola Mundo!”
• Que antes del “¡Hola Mundo!”, se muestre un mensaje que diga que se está por ver
un mensaje y similarmente, luego del “¡Hola Mundo!” se muestre el siguiente el
siguiente mensaje “Un mensaje ha sido mostrado”.

En sí, la salida buscada para nuestro sistema es la siguiente:

“Ahora se mostrará un mensaje”


“¡Hola Mundo!”
“Un mensaje ha sido mostrado”

“¡Hola Mundo!” representará la funcionalidad básica del sistema, mientras que los
mensajes antes y después constituirán el aspecto de logging.

Podríamos pensar en la siguiente clase para representar la funcionalidad básica:

public class HM {
private String mensaje;
public HM() {
this.mensaje = "¡Hola Mundo!";
}
public void setMensaje(String M){
this.mensaje = M;
}
public String getMensaje(){
return this.mensaje;
}
public void showMensaje(){
System.out.println(this.mensaje);
}
}

La clase HM tiene un campo privado mensaje, que es inicializado con ¡Hola Mundo! en
su constructor. Como el campo es privado, esta clase brinda dos métodos para manejar
el mensaje, setMensaje y getMensaje, para setear un nuevo mensaje y para accederlo,
reespectivamente. Por último, cuenta con el método showMensaje para mostrar el
mensaje por pantalla.

Nos queda solamente poner la clase principal, la cual usará la clase HM. La clase
principal se muestra en el siguiente cuadro.

public class HolaMundo {

public static void main(String[] args) {


HM H;
H= new HM();
H.showMensaje();
}
}
Bien, nos queda implementar el aspecto de logging. El comportamiento que agrega este
aspecto es el de imprimir un mensaje antes y otro después, de que se imprima el
mensaje "¡Hola Mundo!”. Nos queda determinar dónde se agrega este comportamiento.
Esto es, nos queda determinar el joinpoint, el punto de enlace entre el código de
aspectos y el código funcional. Para nuestro sistema son las llamadas al método
showMensaje de la clase HM. En AspectJ, nuestro pointcut quedará definido así:

pointcut mensajesAImprimir() : call (void HM.showMensaje());

El pointcut mensajesAImprimir captura todas las llamadas al método showMensaje de la


clase HM.

Ahora que ya tenemos especificado el pointcut, tenemos que agregar el


comportamiento de los aspectos. Dado un poincut, el comportamiento puede agregarse
en tres momentos claves: antes del poincut, después del pointcut, o en lugar del
pointcut. El constructor encargado del comportamiento es el advice. En nuestro
ejemplo, necesitamos agregar comportamiento antes y después de nuestro poincut
mensajesAImprimir. Los advices, quedan entonces definidos así:

before(): mensajesAImprimir(){
System.out.println("Ahora se mostrará un mensaje");
}
after(): mensajesAImprimir(){
System.out.println("Un mensaje ha sido mostrado");
}

Antes y después del pointcut se imprimirán los mensajes correspondientes.

El aspecto de logging queda entonces especificado así:

public aspect Logging {

pointcut mensajesAImprimir() : call (void HM.showMensaje());

before(): mensajesAImprimir(){
System.out.println("Ahora se mostrará un mensaje");
}
after(): mensajesAImprimir(){
System.out.println("Un mensaje ha sido mostrado");
}

De esta manera, tenemos una funcionalidad básica “limpia”, donde todo el código se
refiere a la implementación de la funcionalidad básica solamente. Por otro lado,
tenemos completamente encapsulado nuestro aspecto de logging. Cualquier
modificación sobre el logging será mucho más sencilla debido a que su código está
correctamente encapsulado.
Sin POA, nuestro sistema hubiera quedado así:

public class HolaMundo {

public static void main(String[] args) {


HM H;
H= new HM();
System.out.println("Ahora se mostrará un mensaje");
H.showMensaje();
System.out.println("Un mensaje ha sido mostrado");
}
}

El código de logging, mostrado en rojo en la figura, entrecruza el código de la


funcionalidad básica, lo cual trae muchos y complejos problemas, especialmente para la
evolución y mantenimiento de nuestro sistema, disminuyendo la calidad del código.

Este ejemplo fue implementado en el entorno AJDT AspectJ Development Tools,


(versión AJDT 1.3 para Eclipse 3.1). Este entorno es muy útil y práctico para programar
en aspectos. Lo que me resultó más interesante es la manera gráfica de mostrar el
comportamiento de los aspectos. Las siguientes capturas de pantalla muestran esto.

En la figura de arriba podemos ver los aspectos que interactúan con el método
showMensaje de la clase HM. Para el método, nos dice qué advices interactúan con él, y
cuándo. En este caso, los advices before y after del aspecto logging, y también el
nombre del pointcut involucrado (mensajesAImprimir).

El punto de vista del aspecto lo refleja la siguiente figura. En la misma vemos donde y
cómo se usa el poincut mensajesAImprimir. Nos dice que existe un advice que
aparecerá antes del showMensaje de la clase HM y otro después.

Esta es una manera muy clara, útil y natural de expresar el comportamiento de los
aspectos sobre el código base. Podemos ver estando en el código base donde se meterán
los aspectos, y del lado de los aspectos, podemos ver donde se aplicarán en el código
fuente.

Aquí les dejo links interesantes para seguir con AspectJ y Programación Orientada a
Aspectos.

• http://www.eclipse.org Página de Eclipse.


• http://www.eclipse.org/aspectj/ Página de AspectJ.
• http://www.eclipse.org/ajdt/ Entorno AspectJ en Eclipse. (AJDT) AspectJ
Development Tools
• http://www-128.ibm.com/developerworks/library/j-ajdt/ Artículo en inglés con una
buena itroducción a AJDT.

En la página siguiente solucionaremos el problema mediante el uso de metadatos y


anotaciones, combinado con técnicas AOP. Los advices quedan igual, sin ningún
cambio, sólo cambian los pointcuts, ya que ahora no están basados en la sintaxis del
código, sino en las anotaciones. El pointcut está definido ahora de la siguiente forma:

pointcut mensajesAImprimir() : call(@mensajeAImprimir * *.*(..));


AOP puede combinarse con otras técnicas y herramientas. En este caso, analizamos y
mostramos cómo AOP puede combinarse con la metodología de metadatos y
anotaciones. El ejemplo de implementación será una nueva versión del “¡Hola
Mundo!”, pero esta, mediante una solución anotada.

Los metadatos son datos sobre datos. Muchos tenemos la intuición que un sistema es
más que la frágil sintaxis de sus instrucciones. La sintaxis como sabemos es muy
proclive a cambios, y esto ocasiona numerosos problemas. Una de la manera de hacer
más fuerte el contenido de nuestro sistema es agregándole semántica al código, de
manera de depender de algo más robusto que la sintaxis. De eso se trata los metadatos.

En el contexto de lenguajes de programación, los metadatos son información extra que


se agrega a los elementos de un programa. En su nivel más básico, puede ser
simplemente una etiqueta que permita establecer, por ejemplo, si un método pertenece o
no a las reglas de negocio del sistema. La forma de llevar a cabo la noción de
metadatos es a través de las anotaciones. Las anotaciones permiten establecer
relaciones entre los elementos de un programa, formando una capa superior de
abstracción, de más alto nivel. Es decir, permiten agregar semántica y significado a
nuestro código. Las anotaciones ya son un constructor por defecto en la última versión
de JAVA: J2SE 5.0 (Tiger), y también existe su equivalente en lenguajes sobre .Net
como C#. Asimismo, la última versión de AspectJ, AspectJ 5, incorpora la noción de
anotaciones a su núcleo básico de operadores. Un informe completo sobre
metaprogramación y anotaciones escapa a este artículo, en el cual simplemente nos
concentraremos en mostrar un ejemplo en AspectJ basado en el uso de anotaciones.
Sobre el final del artículo, se mencionan links a páginas con material adicional y más
completo sobre anotaciones y metaprogramación.

Pasemos ahora a detallar la solución a nuestro problema a través de anotaciones. A la


hora de encarar la especificación del aspecto, debemos pensar de otra manera. Mis
aspectos ahora no estarán basados en la sintaxis del código, sino en las anotaciones.
Debo, por lo tanto, crear mis anotaciones, y asociarlas con el código base. Para nuestro
aspecto de logging, necesitamos una anotación para establecer qué mensajes queremos
loguear. La anotación constituye un tipo más para nuestro sistema, y se crean de una
manera muy similar a las interfaces. La anotación que necesitamos es bastante simple,
muy parecido a una etiqueta. El código AspectJ que la define es el siguiente:

public @interface mensajeAImprimir {};

Con esta declaración, se crea un nuevo tipo a nuestro sistema, la anotación


mensajeAImprimir.

Ahora, debemos anotar las porciones de código relacionadas con los mensajes a
imprimir. En nuestro caso, la porción de código que queremos anotar es el método
showMensaje de la clase HM. La anotación se hace a través del carácter especial @ de
la siguiente manera:
public class HM {…
@mensajeAImprimir
public void showMensaje(){
System.out.println(this.mensaje);
}
}

Con esta anotación se establece que el método showMensaje forma parte del conjunto
de métodos que me interesa loguear. Este conjunto representa un nivel más de
abstracción, más sólido que la sintaxis del código. Por lo tanto, los aspectos basados en
este nivel superior, son más reusables y evolucionables. Es decir, yo puedo cambiar el
nombre del método, o sus parámetros, o cualquier otro detalle sintáctico, pero mientras
siga siendo parte de los métodos que quiero logear, la anotación mantendrá su
significado y el aspecto no se verá afectado por los cambios sintácticos. Claramente
constituye un avance importante.

Bien, sólo nos queda mostrar cómo es la especificación de los aspectos basados en
anotaciones.

pointcut mensajesAImprimir(): call(@mensajeAImprimir * *.*(..));

Este pointcut captura todas las llamadas a métodos anotados con la anotación
mensajeAImprimir. El aspecto queda definido así:

public aspect Logging {

pointcut mensajesAImprimir(): call(@mensajeAImprimir * *.*(..));

before(): mensajesAImprimir(){
System.out.println("Ahora se mostrará un mensaje");
}
after(): mensajesAImprimir(){
System.out.println("Un mensaje ha sido mostrado");
}

Como establecimos anteriormente, este nuevo aspecto está basado sobre las
anotaciones, y es “resistente” a modificaciones sintácticas. Pero no todo lo que brilla es
oro. La contra que tienen las anotaciones es que se suele caer en la tentación de abusar
de ellas. Si esto ocurre, las anotaciones terminan ensuciando mucho nuestro código,
insertando cosas extras que luego no se entienden. Siempre teniendo en mente que las
anotaciones son un arma extra que tiene el programador para hacer más robusto y
confiable su código, los riesgos de que surjan los efectos negativos de las anotaciones
son casi nulos. Las anotaciones deben tener sentido, para así formar una visión más
abstracta del código, con más significado que la sintaxis del código.

S-ar putea să vă placă și