Comparación de Spring AOP y AspectJ

1. Introducción

Hay varias bibliotecas de AOP disponibles en la actualidad, y estas deben poder responder una serie de preguntas:

  • ¿Es compatible con mi aplicación nueva o existente?
  • ¿Dónde puedo implementar AOP?
  • ¿Qué tan rápido se integrará con mi aplicación?
  • ¿Cuál es la sobrecarga de rendimiento?

En este artículo, veremos cómo responder estas preguntas e introducir Spring AOP y AspectJ, los dos frameworks AOP más populares para Java.

2. Conceptos de AOP

Antes de comenzar, hagamos una revisión rápida y de alto nivel de los términos y conceptos básicos:

  • Aspecto: un código / función estándar que se encuentra disperso en varios lugares de la aplicación y, por lo general, es diferente de la lógica empresarial real (por ejemplo, la gestión de transacciones). Cada aspecto se centra en una funcionalidad transversal específica
  • Punto de unión: es un punto particular durante la ejecución de programas como la ejecución de métodos, la llamada al constructor o la asignación de campos.
  • Aviso: la acción realizada por el aspecto en un punto de unión específico
  • Pointcut: una expresión regular que coincide con un punto de unión. Cada vez que un punto de unión coincide con un punto, se ejecuta un consejo específico asociado con ese punto.
  • Tejido: el proceso de vincular aspectos con objetos específicos para crear un objeto recomendado.

3. Spring AOP y AspectJ

Ahora, analicemos Spring AOP y AspectJ en varios ejes, como capacidades, objetivos, tejido, estructura interna, puntos de unión y simplicidad.

3.1. Capacidades y metas

En pocas palabras, Spring AOP y AspectJ tienen diferentes objetivos.

Spring AOP tiene como objetivo proporcionar una implementación AOP simple en Spring IoC para resolver los problemas más comunes que enfrentan los programadores. No está pensado como una solución AOP completa , solo se puede aplicar a beans que son administrados por un contenedor Spring.

Por otro lado, AspectJ es la tecnología AOP original que tiene como objetivo proporcionar una solución AOP completa. Es más robusto pero también significativamente más complicado que Spring AOP. También vale la pena señalar que AspectJ se puede aplicar a todos los objetos de dominio.

3.2. Costura

Tanto AspectJ como Spring AOP utilizan el tipo diferente de tejido que afecta su comportamiento en cuanto al rendimiento y la facilidad de uso.

AspectJ utiliza tres tipos diferentes de tejido:

  1. Tejido en tiempo de compilación : el compilador AspectJ toma como entrada tanto el código fuente de nuestro aspecto como nuestra aplicación y produce archivos de clase tejidos como salida
  2. Tejido posterior a la compilación : esto también se conoce como tejido binario. Se utiliza para tejer archivos de clases existentes y archivos JAR con nuestros aspectos.
  3. Tejido en tiempo de carga : esto es exactamente como el tejido binario anterior, con la diferencia de que el tejido se pospone hasta que un cargador de clases carga los archivos de clase en la JVM

Para obtener información más detallada sobre AspectJ en sí, consulte este artículo.

Como AspectJ usa el tiempo de compilación y el tiempo de carga de clases, Spring AOP hace uso del tiempo de ejecución .

Con el tejido en tiempo de ejecución, los aspectos se entrelazan durante la ejecución de la aplicación utilizando proxies del objeto objetivo, utilizando un proxy dinámico JDK o un proxy CGLIB (que se tratan en el siguiente punto):

3.3. Estructura interna y aplicación

Spring AOP es un marco AOP basado en proxy. Esto significa que para implementar aspectos en los objetos de destino, creará proxies de ese objeto. Esto se logra mediante una de dos formas:

  1. Proxy dinámico JDK: la forma preferida para Spring AOP. Siempre que el objeto de destino implemente incluso una interfaz, se utilizará el proxy dinámico JDK
  2. Proxy CGLIB: si el objeto de destino no implementa una interfaz, se puede usar el proxy CGLIB

Podemos obtener más información sobre los mecanismos de proxy de Spring AOP en los documentos oficiales.

AspectJ, por otro lado, no hace nada en tiempo de ejecución ya que las clases se compilan directamente con aspectos.

Y a diferencia de Spring AOP, no requiere ningún patrón de diseño. Para tejer los aspectos del código, introduce su compilador conocido como compilador AspectJ (ajc), a través del cual compilamos nuestro programa y luego lo ejecutamos suministrando una pequeña biblioteca en tiempo de ejecución (<100K).

3.4. Puntos de unión

En la sección 3.3, mostramos que Spring AOP se basa en patrones de proxy. Debido a esto, necesita crear una subclase de la clase de Java objetivo y aplicar las preocupaciones transversales en consecuencia.

Pero viene con una limitación. No podemos aplicar preocupaciones (o aspectos) transversales entre clases que son "finales" porque no se pueden anular y, por lo tanto, daría lugar a una excepción de tiempo de ejecución.

Lo mismo se aplica a los métodos estáticos y finales. Los aspectos de resorte no se les pueden aplicar porque no se pueden anular. Por lo tanto, Spring AOP debido a estas limitaciones, solo admite puntos de unión de ejecución de métodos.

Sin embargo, AspectJ teje las preocupaciones transversales directamente en el código real antes del tiempo de ejecución. A diferencia de Spring AOP, no requiere subclasificar el objeto de destino y, por lo tanto, también admite muchos otros puntos de unión. A continuación se muestra el resumen de los puntos de unión admitidos:

Joinpoint Spring AOP compatible AspectJ compatible
Método de llamada No si
Ejecución del método si si
Llamada al constructor No si
Ejecución del constructor No si
Ejecución del inicializador estático No si
Inicialización de objeto No si
Referencia de campo No si
Asignación de campo No si
Ejecución del controlador No si
Ejecución de asesoramiento No si

También vale la pena señalar que en Spring AOP, los aspectos no se aplican al método llamado dentro de la misma clase.

Eso es obviamente porque cuando llamamos a un método dentro de la misma clase, entonces no estamos llamando al método del proxy que proporciona Spring AOP. Si necesitamos esta funcionalidad, entonces tenemos que definir un método separado en diferentes beans o usar AspectJ.

3.5. Sencillez

Spring AOP es obviamente más simple porque no introduce ningún compilador o tejedor adicional entre nuestro proceso de compilación. Utiliza el tejido en tiempo de ejecución y, por lo tanto, se integra perfectamente con nuestro proceso de construcción habitual. Aunque parece simple, solo funciona con beans administrados por Spring.

Sin embargo, para usar AspectJ, debemos introducir el compilador AspectJ (ajc) y volver a empaquetar todas nuestras bibliotecas (a menos que cambiemos a postcompilación o tejido en tiempo de carga).

Esto es, por supuesto, más complicado que el primero, porque introduce AspectJ Java Tools (que incluyen un compilador (ajc), un depurador (ajdb), un generador de documentación (ajdoc), un navegador de estructura de programa (ajbrowser)) que necesita integrarse con nuestro IDE o la herramienta de compilación.

3.6. Actuación

En lo que respecta al rendimiento, el tejido en tiempo de compilación es mucho más rápido que el tejido en tiempo de ejecución . Spring AOP es un marco basado en proxy, por lo que existe la creación de proxies en el momento del inicio de la aplicación. Además, hay algunas invocaciones de método más por aspecto, lo que afecta negativamente al rendimiento.

Por otro lado, AspectJ teje los aspectos en el código principal antes de que se ejecute la aplicación y, por lo tanto, no hay una sobrecarga de tiempo de ejecución adicional, a diferencia de Spring AOP.

Por estas razones, los puntos de referencia sugieren que AspectJ es casi de 8 a 35 veces más rápido que Spring AOP.

4. Resumen

Esta tabla rápida resume las diferencias clave entre Spring AOP y AspectJ:

Primavera AOP AspectoJ
Implementado en Java puro Implementado usando extensiones del lenguaje de programación Java
No es necesario un proceso de compilación independiente Necesita el compilador AspectJ (ajc) a menos que LTW esté configurado
Solo está disponible el tejido en tiempo de ejecución El tejido en tiempo de ejecución no está disponible. Admite tejido en tiempo de compilación, poscompilación y tiempo de carga
Menos potente: solo admite tejido a nivel de método Más potente: puede tejer campos, métodos, constructores, inicializadores estáticos, clases / métodos finales, etc.
Solo se puede implementar en beans administrados por el contenedor Spring Se puede implementar en todos los objetos de dominio.
Solo admite cortes de puntos de ejecución de métodos Soporta todos los puntos
Los proxies se crean a partir de objetos específicos y los aspectos se aplican a estos proxies Los aspectos se entrelazan directamente en el código antes de que se ejecute la aplicación (antes del tiempo de ejecución)
Mucho más lento que AspectJ Mejor presentación
Fácil de aprender y aplicar Comparativamente más complicado que Spring AOP

5. Elección del marco adecuado

Si analizamos todos los argumentos presentados en esta sección, comenzaremos a comprender que no es en absoluto que un marco sea mejor que otro.

En pocas palabras, la elección depende en gran medida de nuestros requisitos:

  • Framework: si la aplicación no usa Spring Framework, entonces no tenemos otra opción que descartar la idea de usar Spring AOP porque no puede administrar nada que esté fuera del alcance de Spring Container. Sin embargo, si nuestra aplicación se crea completamente usando el marco Spring, entonces podemos usar Spring AOP ya que es sencillo de aprender y aplicar.
  • Flexibilidad: dado el soporte limitado de joinpoint, Spring AOP no es una solución AOP completa, pero resuelve los problemas más comunes que enfrentan los programadores. Aunque si queremos profundizar más y explotar AOP a su máxima capacidad y queremos el soporte de una amplia gama de puntos de unión disponibles, AspectJ es la elección.
  • Rendimiento: si utilizamos aspectos limitados, existen diferencias triviales en el rendimiento. Pero a veces hay casos en los que una aplicación tiene más de decenas de miles de aspectos. No querríamos usar el tejido en tiempo de ejecución en tales casos, por lo que sería mejor optar por AspectJ. Se sabe que AspectJ es de 8 a 35 veces más rápido que Spring AOP
  • Lo mejor de ambos: Ambos marcos son totalmente compatibles entre sí. Siempre podemos aprovechar Spring AOP siempre que sea posible y aún usar AspectJ para obtener soporte de puntos de unión que no son compatibles con el primero.

6. Conclusión

En este artículo, analizamos tanto Spring AOP como AspectJ, en varias áreas clave.

Comparamos los dos enfoques de AOP tanto en flexibilidad como en la facilidad con la que encajarán con nuestra aplicación.