Programación orientada a aspectos con AspectJ, Spring AOP y la clase Proxy
Escrito por
el .
java
planeta-codigo
Enlace permanente
Comentarios
Los aspectos permiten separar código con distintas funcionalidades y centralizar un código común que sin utilizarlos está repartido por toda la aplicación. Son un concepto potente y una vez entendidos sus conceptos ofrecen muchas posibilidades para simplificar el código y mejorar su mantenimiento. Hay varias posibilidades, dos de las más utilizadas son AspectJ y Spring AOP, en el caso de que estas no se puedan utilizar el JDK incluye la clase Proxy para usos básicos aunque más limitados.
Ciertas funcionalidades son transversales y están repartidas por toda la aplicación. Añadir y mezclar el código de esta funcionalidades con el código en los métodos hace que el código del método sea más complicado incluso puede que ese código de utilidad sea de mayor tamaño que el fundamental del método.
Algunos ejemplos de funcionalidades transversales son trazas, métricas de rendimiento, seguridad, caches o transacciones. La programación orientada a aspectos es una técnica de programación que permite extraer este código transversal y aplicarlo en aquellos puntos de la aplicación donde sea necesario sin estar mezclado con el código al que se aplica. Un aspecto es el código transversal de utilidad aplicable a varios puntos de la aplicación. Esto facilita la legibilidad del código, su mantenimiento y la separación de conceptos.
La programación orientada a aspectos se usa mucho en las aplicaciones que usan Spring pero hay otras librerías que lo permiten, incluso el propio JDK tiene alguna clase sin necesitar de dependencias adicionales.
La programación define varios términos:
- Aspect: es una funcionalidad genérica aplicable a múltiples objetos. Cada aspecto trata una sola funcionalidad.
- Join point: es el punto de ejecución donde se puede aplicar un aspecto como la llamada a un método, su retorno o el acceso a una propiedad.
- Advice: es la acción que se realiza en un pointcut.
- Pointcut: es una expresión que busca joint points, tiene un advice asociado que se ejecuta en todos los joint points que concuerdan con la expresión.
- weaving: proceso que aplica los aspectos a las clases, puede ser en tiempo de compilación o en tiempo de ejecución.
Esta es una clase normal con un método en la que a modo de ejemplo en la llamada al método se le apliquen dos aspectos, uno para añadir una traza cuando se llame al método y su valor de retorno y otro aspecto para medir cuando tiempo tarda en ejecutarse. La clase Foo desconoce los aspectos que se van a aplicar, no hay que hacer ninguna modificación en ella ni para añadirle los aspectos ni para quitarselos.
|
|
La interfaz solo es necesaria para un aspecto implementado con la clase Proxy de Java.
|
|
Se recomienda usra la forma más simple que sea suficiente para las necesidad de la aplicación. Spring AOP es más simple que usar AspectJ y no hay necesidad de aplicar el compilador de AspectJ en el proceso de compilación. Si solo se necesita aplicar advices en la ejecución de métodos de beans de Spring, Spring AOP es suficiente.
Si no se usa spring o se necesitan aplicar aspectos en objetos no gestionados por el contenedor de Spring (como objetos de dominio) o aplicar advices en joint points distintos a las ejecuciones de métodos, por ejemplo para la obtención o asignación de una propiedad entonces la opción a usar es AspectJ.
Contenido del artículo
Programación orientada a aspectos con AspectJ
AspectJ es una librería específica y la que más posibilidades ofrece de las que muestro en el artículo. Hay varias formas de utilizar AspectJ, la de usarla mediante anotaciones es bastante simple.
Una de las ventajas de AspectJ es que no requiere usar Spring para utilizarla pero para ello en el momento de compilación hay que realizar un proceso denominado weaving para añadir la funcionalidad de los aspectos que transformar el bytecode de las clases. Aplicar los aspectos transformando el código permite que los aspectos no penalicen en tiempo de ejecución y ofrezca mejor rendimiento que Spring AOP, aunque el rendimiento no es algo determinante en la mayoría de los proyectos. Por contra es más compleja y requiere aplicar a las clases un proceso de postcompilación.
Las expresiones de los ponintcuts son similares a una definición de la firma del los métodos, ámbitos de visibilidad, tipos de parámetros y tipo de retorno además del paquete. Es posible hacer expresiones boleanas compuestas para hacer más especifica una expresión. Este pointcut se aplica en la ejecución del método sum de la clase Foo que recibe dos parámetros de tipo int y retorna un valor de tipo int.
|
|
En la clase Aspects se definen los aspectos con una colección de pointcuts con sus código de advice asociado.
|
|
Con la herramienta de construcción Gradle hay que incluir un plugin para aplicar el proceso de weaving. El proceso de weaving consiste en aplicar los aspectos a las clases, AspectJ lo realiza en tiempo de compilación modificando el bytecode de las clases en un segundo paso de compilación, con anterioridad el compilador de Java ha transformado el código fuente de las clases en bytecode.
|
|
|
|
En la salida del programa para el apartado de AspectJ se observa que el código de los aspectos se ejecuta al llamar a los métodos de la instancia de la clase Foo.
|
|
Programación orientada a aspectos con Spring AOP
Spring incluye su solución para la programación orientada a aspectos, más limitada que AspectJ pero suficiente para la mayoría de los casos tampoco requiere aplicar el proceso weaving de AspectJ en tiempo de compilación. La limitación de Spring AOP es que los joint points solo pueden ser métodos. Utiliza las mismas anotaciones de AspectJ para aplicar los aspects en tiempo de ejecución.
Otra diferencia con AspectJ es que los aspectos se aplican usando proxys que son una clase que envuelve a la instancia a la que se le aplica el aspecto, una vez dentro de la clase objetivo si se llama a otro método de forma interna a ese otro método no se le aplica su aspecto.
Suponiendo una clase que tiene un método foo y bar y desde fuera se llama a foo y este llama a bar para que en llamada desde foo a bar se apliquen los aspectos de bar hay que usar este código. Usar este código implica poner en el código una dependencia a Spring, lo cual no es deseable para el código de dominio.
|
|
En el proxy es donde se ejecuta el código del advice.
Para que Spring procese las anotaciones require usar la anotación @EnableAspectJAutoProxy y que Spring encuentre la clase de los aspectos, anotándola con @Component o devolviendo una instancia en el contenedor de dependencias como en este caso.
|
|
El plugin para realizar el proceso de weaving con AspectJ no es necesario. Spring realiza el proceso de weaving en tiempo de ejecución.
|
|
El resultado es el mismo que con AspectJ.
|
|
Programación orientada a aspectos con la clase Proxy
Para casos muy sencillos donde no sea posible aplicar una de las opciones anteriores al no poder usar sus librerías por restricciones del proyecto en cuanto a dependencias usables está la alternativa incluida en el JDK. La clase Proxy está incorporada en el propio JDK, permite hacer cosas sencillas sin dependencias adicionales.
|
|
|
|
En este caso se observa que se ha aplicado el aspecto de AspectJ y además los aspectos de los proxys de este apartado.
|
|
El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando siguiente comando:./gradlew run