AspectJ, Programación con Aspectos

0
39643

Programación con aspectos: AspectJ

Los que trabajamos con Java habitualmente nos encontramos un grave
problema: 

  • La misma cosa se puede hacer de 20 modos distintos y nadie nos dice cual
    es el más adecuado. Además como evoluciona todo tan deprisa, lo que eran
    verdad (o podríamos pensar) hace unos meses, es posible que ahora no lo
    sea.

Hoy vamos a hablar de otro planteamiento de contrucción de aplicaciones, la
denominada programación por aspectos.

Cuando construimos una aplicación, normalmente nuestros procesos de negocio
realizan una serie de tareas:

  1. Verificación de credenciales.
  2. Verificación de precondiciones.
  3. Comienzo de una transacción.
  4. Ejecución de nuestra función de negocio.
  5. Finalización de una transacción.
  6. Verificación de post-condiciones.
  7. Y además, sin un orden concreto, escritura de trazas, medida de la
    velocidad, etc.

De todos los puntos anteriores, solo el punto 4 es realmente nuestra función
de negocio.

El problema ahora es que si queremos quitar, poner o modificar algunas de las
otras funcionalidades colatorales, tenemos un grave problema… tocar mucho
código.

Quitar la funcionalidad o hacer que no se ejecute en un momento determinado
(en base a un parámetro),  puede ser relativamente fácil pero ¿cómo
hacemos para introducir o cambiar esta funcionalidad sin tocar nuestros
programas?… y para que nadie se lie con patrones de diseño (factorías y
similares) pongamos que queremos calcular en tiempo de ejecución de todas las
funciones en nuestro programa ….. JEJEJE…… esto ya no es tan fácil
¿verdad?.

¿Cual es la solución? Una de ellas es separar los distintos aspectos
de las aplicaciones.

Antes de entrar en teoría, vamos a instalar el software y verlo en un
ejemplo.

Instalación de AspectJ

AspectJ es una extensión de Java que podemos encontrar en Eclipse.org.

Nos descargamos el Jar y lo ejecutamos.

Nos aparece el instalador…

Seleccionamos la máquina virtual a ejecutar

Elegimos es directorio de trabajo

Y debemos tocar las variables de entorno de nuestro sistema …

Incluimos en el classpath el jar : c:\java\aspectj1.1\lib\aspectjrt.jar
y el en path el directorio bin: c:\java\aspectj1.1\bin

Si vamos al directorio de instalación, podemos encontrar el entorno de
desarrollo de AspectJ

Es aspecto inicial es el siguiente. Pulsamos el símbolo + para añadir
un nuevo fichero de configuración.

Ahora vamos a cargar uno de los ejemplos para comprobar que el sistema
funciona.

Pulsamos el icono Build (construir)

En este caso se compila el sistema….

Ahora, seleccionamos la clase que tiene un método main (tracing.ExampleMain)

Y podemos ver que aparece el la ventana unos mensajes extraños…..

Esto significa que el sistema está funcionando… ahora vamos a crear
nuestro propio ejemplo.

Ejemplo de AspectJ

Vamos a crear un programa sencillo, que tiene una función que nos interesa
saber cuanto tarda en ejecutarse ….

(Nota: Que nadie piense que esta tecnología vale pra optimizar o medir
velocidad…. podemos utilizarlo para realizar un control de parámetros, flujo
de navegación, obtención de pools, paginación, persistencia…. y lo que se
nos ocurra…  )

public class adictosaltrabajo
{
    public static void main(String[] args) 
    {
	adictosaltrabajo programa = new adictosaltrabajo();
	programa.procesa();
	System.out.println("Hemos terminado");
    }

    public void procesa()
    {
	long total = 0;

	// ejecutamos un bucle simple
	for(int i=0;i<10000000;i++)
	{
		total = total + 5 /2 * 7 -4;
	}

    }
}
      

Si compilamos la clase y la ejecutamos obtenemos el siguiente resultado:

Imaginad que ahora queremos saber el tiempo que tarda en
ejecutarse la función procesa….

Gracias a AspectJ podemos crear un nuevo aspecto que interactúe
con el código existente en base a unas reglas.

Lo que vamos a hacer es «pinchar» la llamada a la
función y establecer un contador… todo esto sin tocar la lógica existente…

Editamos clase que define el aspecto:


import java.util.*;

aspect miaspecto
{
    private long tiempo = 0;
 
    pointcut mipuntotraza(): execution(* adictosaltrabajo.procesa(..));
  
    before (): mipuntotraza() 
    {
	System.out.println("Entramos en funcion: " + thisJoinPoint);
	tiempo = System.currentTimeMillis();
    }

   after(): mipuntotraza() 
    {
        System.out.println("Salimos de funcion: "  + thisJoinPoint + 
           " y hemos tardado" + (System.currentTimeMillis() - tiempo ));
     }

}
   

Lo que estamos definiendo es un comportamiento:

Cuando crucemos nuestra clase con este aspecto, en el punto de
corte

 pointcut
mipuntotraza(): execution(*
adictosaltrabajo.procesa(..));

definimos que cuando se ejecute la función procesa,
ejecutaremos una función llamada mipuntotraza.

Antes de ejecutar esta nuevo función 

before (): mipuntotraza()

definimos un contador

Y despues, calculamos el tiempo que ha tardado en ejecutarse

after(): mipuntotraza()

Ahora, copiamos los dos ficheros a un directorio y creamos un
tercer fichero llamado milista.lst

Arrancamos el browser de AspectJ y le decimos que utilice este
fichero .lst

Y pulsamos el botón build y vemos que el sistema ha
identificado este punto de cruce

Configuramos en las opciones que queremos ejecutar nuestra clase
java

Y ejecutamos…. la sorpresa es que se ejecuta nuestra clase …
pero el sistema nos dice lo que ha tardado en ejecutarse

Podemos decompilar el código de nuestra clase
adictosaltrabajo.class
y ver como le ha afectado el uso de AspectJ

public class adictosaltrabajo
{

    public adictosaltrabajo()
    {
    }

    public static void main(String args[])
    {
        adictosaltrabajo programa = new adictosaltrabajo();
        programa.procesa();
        System.out.println("Hemos terminado");
    }

    public void procesa()
    {
        Object aobj[];
        org.aspectj.lang.JoinPoint joinpoint = Factory.makeJP(ajc$tjp_0, this, this, aobj = new Object[0]);
        try
        {
            miaspecto.aspectOf().ajc$before$miaspecto$96(joinpoint);
            long total = 0L;
            for(int i = 0; i < 0x989680; i++)
                total = (total + 14L) - 4L;

        }
        catch(Throwable throwable)
        {
            miaspecto.aspectOf().ajc$after$miaspecto$125(joinpoint);
            throw throwable;
        }
        miaspecto.aspectOf().ajc$after$miaspecto$125(joinpoint);
    }

    public static final org.aspectj.lang.JoinPoint.StaticPart ajc$tjp_0;

    static 
    {
        Factory factory = new Factory("adictosaltrabajo.java", Class.forName("adictosaltrabajo"));
        ajc$tjp_0 = factory.makeSJP("method-execution", factory.makeMethodSig("1-procesa-adictosaltrabajo----void-"), 13);
    }
}
      

Es decir, se ha generado un código binario combinado
(respetando nuestro fuente original), añadiendo los nuevos aspectos …….

La verdad que es sorprendente …… y profundizaremos con usos
más avanzados porque creo que esta tecnología tiene mucho futuro…..

Sobre
el Autor ..

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad