Programación orientada a aspectos con Spring
Introducción
La AOP (programación orientada a aspectos) añade nociones de transversalidad, que no están disponibles en la programación orientada a objetos (POO). Esta transversalidad se centra en aspectos que permiten añadir un procesamiento específico cuando se ejecuta un tipo de evento sobre un conjunto de objetos. Por lo tanto, es posible añadir aspectos como la gestión de transacciones, que es transversal a un conjunto de objetos. Spring utiliza mucho la AOP de forma transparente. Su uso en nuestros proyectos es independiente del kernel Spring. La librería Spring AOP solo se añade si es necesario.
A menudo encontramos AOP en los frameworks de nuestros clientes. Es raro que se utilice para codificar reglas de negocio porque requiere un diseño especial. Para una funcionalidad que agrupa varias entidades, generalmente es preferible copiar/pegar.
En lugar de usar un design pattern proxy, generalmente usamos el design pattern del decorador.
Decorador:
El design pattern del decorador es muy bueno, en general, porque permite especializar los objetos. Por otro lado, Java no admite la herencia múltiple y en diamante (sobre las clases).
No es posible heredar variables de más de una clase. Sin embargo, se permite la herencia de métodos de varias interfaces a través de interfaces y métodos default.
Antes de estudiar la AOP con Spring, veamos cómo modificar las clases sin la ayuda de Spring. Para hacer esto, podemos utilizar los proxys.
Si quiere ver lo que está pasando detrás de la escena, puede consultar las fuentes de los JDK (https://github.com/openjdk/jdk).
Proxy:
El design pattern proxy permite aumentar una o más clases con métodos y atributos. Escribir un proxy a mano no resulta fácil, pero es posible para una clase gracias a las API de introspección del paquete java.lang.reflect del JDK:
Método |
Utilidad |
Proxy |
Permite crear clases e instancias de proxy dinámicas |
InvocationHandler |
Administrador de llamadas de los métodos en los proxys |
Method |
Información sobre un método |
El Proxy proporciona métodos estáticos para crear clases e instancias de proxy dinámicas, y también es la superclase de todas las clases de proxy dinámicas creadas por estos métodos.
InvocationHandler es la interfaz implementada por el controlador de llamadas de...
¿Por qué AOP?
Veremos que hay una librería para usos sencillos y estándares, y otra específica para usos avanzados que se basa en anotaciones AspectJ.
Al igual que con la configuración clásica del contexto Spring, los aspectos se pueden definir como archivos XML o anotaciones, o una composición de ambos. Por ejemplo: Spring realiza la gestión de transacciones a través de la anotación @Transactional. Esta anotación es un aspecto particular gestionado directamente por Spring.
Los aspectos generalmente se colocan en la base técnica y responden a inquietudes como, por ejemplo, la instrumentación del código. Rara vez se explotan para responder a inquietudes de negocio porque este tipo de programación es compleja a nivel de mantenimiento. Por lo tanto, el código de los tratamientos de AOP debe ser limpio y estar muy bien comentado.
Los métodos llamados a través de AOP se suelen desconectar mediante configuración con anotaciones @Conditional.
Los conceptos de AOP
Spring utiliza la terminología estándar para nombrar sus elementos relativos a la AOP, incluso si no es muy intuitiva.
Definiciones
-
Aspecto: modularización de un problema que afecta a un conjunto de clases de forma transversal.
-
Punto de unión (Joinpoint): etapa durante la ejecución de un programa, como ejecutar un método o el procesamiento de una excepción. En Spring AOP, un punto de unión siempre representa la ejecución de un método.
-
Advice: las acciones de interceptación que toma un aspecto en particular en un punto de unión. Los diferentes tipos de acciones son «alrededor de», «antes de» y «después de». Es posible encadenar estos interceptores.
-
Punto de corte (Pointcut): predicado que permite seleccionar puntos de unión mediante una expresión que indica, por ejemplo, el nombre de un método. Spring utiliza el lenguaje AspectJ de forma predeterminada.
-
Injection: permite inyectar dinámicamente campos y métodos adicionales en un objeto. Spring AOP también permite introducir dinámicamente nuevas interfaces con sus implementaciones. Una inyección se conoce como una declaración «inter-types» en la comunidad AspectJ.
-
Objeto de destino (Target object): objeto destino de uno o más aspectos. También se llama objeto orientado a aspecto. Spring siempre...
Límites de Spring AOP y uso de AspectJ
Spring AOP se limita a ejecutar métodos en puntos de unión, que es suficiente en la gran mayoría de los casos de uso. La interceptación en el cambio de estado de los campos de los objetos, por ejemplo, no se tiene en cuenta. En su lugar, AspectJ se utilizará directamente para un uso avanzado.
El soporte @AspectJ en Spring
Usamos este soporte para reutilizar la interpretación de las anotaciones de AspectJ, para la búsqueda y detección de métodos candidatos para un aspecto. Solo se utiliza el soporte de anotaciones. Spring no usa el Weaver de aspectos de AspectJ.
Es muy posible usar AspectJ junto con Spring en casos complejos donde Spring no sería suficiente.
1. Habilitar el soporte
La librería AspectJ aspectjweaver.jar debe estar en el classpath.
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.9.1</version>
</dependency>
2. Habilitación de @AspectJ con configuración XML
Para habilitar el soporte AspectJ con una configuración basada en XML, se debe utilizar el elemento AOP aspectj-autoproxy.
Añada este elemento en la configuración y verifique que existe la definición del AOP:
<beans default-lazy-init="true"
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/aop ...
Las API de bajo nivel para Spring AOP
Este es un ejemplo del uso de las API de bajo nivel. No las mostraremos todas porque se presentan muy bien en la documentación de Spring y será raro que las utilicemos. Las mencionamos porque permiten experimentar con los aspectos de manera muy sencilla.
1. La interfaz PointCut
La interfaz PointCut se corresponde con un punto de corte que permite, a través de una expresión regular, identificar los métodos que serán interceptados.
class MiPointcut implements PointCut {
public ClassFilter getClassFilter() {
return null;
}
public MethodMatcher getMethodMatcher() {
return null;
}
Hay dos métodos en la interfaz:
Clase |
Método |
Utilidad |
ClassFilter |
getClassFilter(); |
Filtrar por clase. |
MethodMatcher |
getMethodMatcher(); |
Hacer Match en la clase. |
2. La interfaz ClassFilter
La interfaz ClassFilter solo contiene un método, que coincide con el método al que se llamará durante la interceptación.
class MiClassFilter implements ClassFilter {
public boolean matches(Class<?> clazz) {
return false;
}
3. La interfaz MethodMatcher
La interfaz MethodMatcher permite...
Puntos clave
-
La programación orientada a aspectos a menudo está presente en las bases de software.
-
Es posible codificar simplemente aspectos.
-
Cuando encontramos una acción en un grupo de clases, debemos ver si podemos usar un aspecto.
-
Los aspectos son confusos; hay que entenderlos bien para poder corregir el código que los utiliza.