Comprender Spring AOP desde una perspectiva de configuración XML

Este artículo es compartido por la comunidad de la nube de Huawei " Spring Master's Road 18: comprensión de Spring AOP desde la perspectiva de la configuración XML ", autor: Zhuan Yeyang__.

1. Spring AOP y proxy dinámico

1.1 La relación entre Spring AOP y el proxy dinámico

Spring AOPImplementar programación orientada a aspectos utilizando proxies dinámicos como mecanismo principal. Este mecanismo permite Springla creación dinámica de objetos proxy en tiempo de ejecución. Estos objetos proxy envuelven el objeto de destino (es decir, el componente comercial) para insertar comportamientos adicionales (como controles de seguridad, gestión de transacciones, registros, etc.) antes y después de llamar a los métodos del objeto de destino. .

  • Proxy dinámico JDKSpring AOP : el proxy dinámico utilizado de forma predeterminada cuando el objeto de destino implementa una o más interfaces JDK. JDKEl proxy dinámico utiliza el mecanismo de reflexión para crear un objeto proxy para la interfaz. Este objeto proxy interceptará todas las llamadas al método de la interfaz de destino.

  • Proxy CGLIB : si el objeto de destino no implementa ninguna interfaz, Spring AOPrecurrirá CGLIBa la biblioteca para generar una subclase de la clase de destino. CGLIB( Code Generation Library) es una poderosa biblioteca de generación de código de alto rendimiento que extiende Javalas clases en tiempo de ejecución y anula los métodos en las subclases para implementar la intercepción de métodos.

Independientemente del método de proxy que se utilice, el propósito es insertar comportamientos adicionales en diferentes etapas de la ejecución del método a través de notificaciones definidas por aspectos sin cambiar el código de lógica de negocios original.

1.2 Terminología básica de AOP

Aspecto : Aspect es el núcleo de la programación orientada a aspectos. Es una construcción que modulariza las preocupaciones en múltiples clases (como registro, gestión de transacciones, etc.). Un aspecto puede contener múltiples tipos de consejos ( Advice) y uno o más puntos ( Pointcut) que definen dónde y cuándo se ejecutan esos consejos.

Punto de unión : un punto de unión representa una ubicación específica durante la ejecución del programa, Spring AOPlo que limita estas ubicaciones a llamadas a métodos. En pocas palabras, un punto de unión es un punto donde se pueden insertar consejos de aspectos.

Consejo : El consejo define la acción que realizará el aspecto en el punto de conexión. Dependiendo del tipo de notificación, estas acciones se pueden realizar antes, después de llamar al método, después de devolver un resultado o cuando se lanza una excepción. Los tipos de notificación incluyen:

  • Notificación previa ( Before advice): ejecutada antes de que se ejecute el método.
  • Notificación posterior ( After advice): Se ejecuta después de ejecutar el método, independientemente de sus resultados.
  • Notificación posterior a la devolución ( After-returning advice): se ejecuta después de que el método se ejecuta correctamente.
  • Notificación posterior a la excepción ( After-throwing advice): se ejecuta después de que el método arroja una excepción.
  • Consejo envolvente ( Around advice): ejecutado antes y después de la ejecución del método, proporcionando control total sobre las llamadas al método.

Pointcut (Pointcut) : Pointcut es una expresión que permite hacer coincidir puntos de conexión a través de nombres de métodos, modificadores de acceso y otras condiciones, lo que determina qué métodos deben activarse cuando se ejecutan las notificaciones.

Objeto de destino : un objeto que es notificado por uno o más aspectos. También llamado objeto proxy.

Proxy AOP : AOPun objeto creado por el marco para implementar contratos de aspectos (definidos por consejos y puntos). En Spring AOP, AOPun proxy puede ser JDKun proxy dinámico o CGLIBun proxy.

Introducción : La introducción permite agregar nuevos métodos o propiedades a una clase existente. Esto se Introduction interfaceslogra definiendo una o más interfaces adicionales (), y AOPel marco crea un proxy para el objeto de destino que implementa estas interfaces.

Si todavía parece abstracto, pongamos otro ejemplo de producción cinematográfica como analogía.

Aspecto

Imagine que alguien está filmando una película y los efectos especiales de la película (como explosiones y efectos especiales de iluminación) son como preocupaciones transversales que deben manejarse en la aplicación (como el registro o la gestión de transacciones). Estos efectos especiales aparecen en muchas escenas diferentes de la película, no sólo en una escena específica. En AOPPython, estos "efectos" son aspectos y se pueden aplicar a múltiples partes del programa sin cambiar la escena (o el código) real.

Punto de unión

Siguiendo con la metáfora cinematográfica, un momento concreto de cada escena, como por ejemplo el momento en que se produce una explosión, puede verse como un punto de conexión. En programación, esto suele corresponder a una llamada a un método.

Consejo

Las notificaciones son como instrucciones específicas del director al equipo de efectos especiales, como "Agregar un efecto de explosión antes de que comience esta escena" o "Muestre el efecto de disipación de humo después de que termine la escena". Estas instrucciones le indican al equipo de efectos especiales qué efectos específicos se deben agregar en momentos específicos de la película. En AOP, estas "instrucciones" son notificaciones que especifican que los aspectos (efectos especiales) deben ejecutarse antes, después o alrededor de los puntos de unión (momentos específicos de ejecución de código).

corte puntual

Si el aviso es la instrucción del director al equipo de efectos especiales, entonces el punto de corte son las condiciones específicas contenidas en la instrucción, como "escenas de locaciones nocturnas". Los puntos de corte definen qué puntos de conexión (como qué llamadas a métodos específicos) deben recibir notificaciones (instrucciones de efectos).

Objeto de destino

Los objetos de destino son aquellas escenas donde es necesario agregar efectos especiales. En nuestra metáfora de la programación, son aquellos objetos que se ven afectados por la lógica de aspecto (como las clases que requieren registro).

Proxy AOP

AOPUn proxy es como una copia virtual controlable de una escena proporcionada por el equipo de efectos especiales. Esta copia le parece al público la misma que la escena original, pero en realidad agrega automáticamente efectos especiales cuando el director los necesita. En programación, un proxy es un AOPobjeto creado automáticamente por el marco. Envuelve el objeto de destino y garantiza que las notificaciones (instrucciones de efectos especiales) se ejecuten en el momento correcto.

Introducción

La introducción es como agregar un personaje o escena completamente nuevo a una película que no existe en el guión original. En AOP, la introducción nos permite agregar nuevos métodos o propiedades a una clase existente, lo que es como ampliar el contenido de una película sin cambiar el guión original.

2. Implementar Spring AOP mediante configuración XML

SpringProporciona AOPsoporte completo y puede XMLdefinir aspectos, notificaciones ( advice) y puntos de acceso ( pointcuts) a través de la configuración. Esto le permite agregar comportamientos adicionales (como registro, gestión de transacciones, etc.) sin modificar el código fuente.

Pasos de implementación:

  1. Agregar dependencias de Springpom.xml : agregue Springel marco y AOPlas dependencias relacionadas al proyecto .

  2. Defina interfaces comerciales y clases de implementación : cree interfaces de lógica empresarial y sus implementaciones, como una clase de servicio simple.

  3. Definir clases de aspecto : cree una clase de aspecto para definir notificaciones previas, posteriores y finales.

  4. XML de configuración : applicationContext.xmlconfigure aspectos, negocios beany AOPetiquetas relacionadas en XML.

2.1 Agregar dependencia de Spring

En pom.xmlel archivo, agregue las siguientes dependencias

<dependencias>
    <dependencia>
        <groupId>org.springframework</groupId>
        <artifactId>contexto de primavera</artifactId>
        <versión>5.3.10</versión>
    </dependencia>
    <dependencia>
        <groupId>org.springframework</groupId>
        <artifactId>primavera-aop</artifactId>
        <versión>5.3.10</versión>
    </dependencia>
    <dependencia>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <versión>1.9.6</versión>
    </dependencia>
</dependencias>

2.2 Definir interfaces comerciales y clases de implementación.

Primero, definimos una interfaz de lógica de negocios MyServicey su implementación MyServiceImpl.

MiServicio.java:

paquete com.ejemplo.demo.aop;
interfaz pública MiServicio {
    String performAction (entrada de cadena) arroja una excepción;
}

MiServicioImpl.java:

paquete com.ejemplo.demo.aop;
clase pública MyServiceImpl implementa MyService {
    @Anular
    acción de cadena pública (acción de cadena) lanza una excepción {
        System.out.println("Realizando acción en MyService: " + acción);
        if ("lanzar".equals(acción)) {
            lanzar una nueva excepción ("Excepción de MyService");
        }
        devolver "Acción realizada: " + acción;
    }
}

2.3 Definir clases de aspecto

A continuación, definimos una clase de aspecto MyAspectque contendrá un aviso previo ( advice) que se ejecuta antes de ejecutar MyServiceel método.performAction

MiAspecto.java:

paquete com.ejemplo.demo.aop;

importar org.aspectj.lang.ProceedingJoinPoint;

clase pública MiAspecto {

    // notificación previa
    vacío público antes del consejo () {
        System.out.println("¡Antes de que se ejecute el consejo!");
    }

    // publicar notificación
    public void afterAdvice() {
        System.out.println("¡Después del consejo se está ejecutando!");
    }

    // Notificar después del regreso
    vacío público después deReturningAdvice (Objeto retVal) {
        System.out.println("¡Después de devolver el aviso se está ejecutando! Valor de retorno: " + retVal);
    }

    // Notificación después de la excepción
    public void afterThrowingAdvice (ex arrojable) {
        System.out.println("¡Después de lanzar el consejo se ejecuta! Excepción: " + ex.getMessage());
    }

    //notificación envolvente
    Objeto público aroundAdvice (ProceedingJoinPoint joinPoint) lanza Throwable {
        System.out.println("Consejos: antes de la ejecución del método");
        Resultado del objeto = nulo;
        intentar {
            resultado = joinPoint.proceed();
        } finalmente {
            System.out.println("Consejos: después de la ejecución del método");
        }
        resultado de devolución;
    }
}

2.4 XML de configuración

Finalmente, necesitamos configurar el contenido anterior y el contenido relacionado en Springel archivo de configuración .applicationContext.xmlbeanAOP

aplicaciónContext.xml:

<?xml versión="1.0" codificación="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--
Lo anterior es la declaración de encabezado del archivo XML, que define la versión y el tipo de codificación del archivo, e introduce el espacio de nombres de Spring beans y AOP.
A través de estos espacios de nombres, podemos usar etiquetas <bean> y <aop:*> en XML.
-->
    <!-- Definiciones de frijoles -->
    <bean id="miServicio" clase="com.example.demo.aop.MyServiceImpl"/>
    <bean id="miAspecto" class="com.example.demo.aop.MyAspect"/>
	<!-- configuración AOP-->
    <aop:config>
        <!-- Definir aspectos y sus notificaciones -->
        <aop:aspecto id="myAspectRef" ref="myAspect">
            <!-- Defina puntos de corte y especifique notificaciones que deben activarse cuando se ejecutan métodos -->
            <aop:pointcut id="serviceOperation" expresión="ejecución(* com.example.demo.aop.MyService.performAction(..))"/>
            <!-- Aplicar notificación previa, especificar operaciones antes de la ejecución del método -->
            <aop:antes método="antesAviso" pointcut-ref="operaciónservicio"/>
            <!-- Aplicar notificación posterior, especificar la operación después de ejecutar el método, si el método se ejecuta correctamente o se lanza una excepción -->
            <aop:after método="afterAdvice" pointcut-ref="servicioOperación"/>
            <!-- Notificación después de que regresa la aplicación, operaciones después de que el método especificado se ejecuta y devuelve con éxito -->
            <aop:método after-returning="afterReturningAdvice" pointcut-ref="serviceOperation" return="retVal"/>
            <!-- Notificación después de una excepción de la aplicación, acción después de que el método especificado genera una excepción -->
            <aop: método after-throwing="afterThrowingAdvice" pointcut-ref="serviceOperation" throwing="ex"/>
            <!-- Aplicar notificaciones circundantes para proporcionar un control completo antes y después de la ejecución del método -->
            <aop:around método="aroundAdvice" pointcut-ref="servicioOperación"/>
        </aop:aspecto>
    </aop:config>
</frijoles>

myService : esta es la lógica empresarial beany apunta a MyServiceImpluna instancia de la clase.

myAspect : Este es el aspecto bean, que apunta a MyAspectuna instancia de la clase.

<aop:config>: Este es AOPel elemento raíz de la configuración. Todas AOPlas configuraciones, incluidas las definiciones de aspectos, los puntos de acceso y los métodos de notificación, deben definirse dentro de este elemento.

Aspecto : Definido a través de <aop:aspect>elementos, contiene una serie de consejos ( advice) y uno o más puntos ( pointcut). Este elemento asocia clases de aspectos (clases que contienen lógica de notificación) con operaciones específicas (cómo y cuándo mejorar el objeto de destino).

Pointcut : a través de <aop:pointcut>la definición de elementos, pointcut se especifica mediante expresión. Cuando necesite controlar con precisión qué métodos activarán notificaciones cuando se ejecuten, debe definir pointcut. Las expresiones Pointcut pueden especificar métodos con mucha precisión, por ejemplo, por nombre de método, tipos de parámetros, anotaciones, etc. expressionDefine la expresión del pointcut y especifica las reglas de coincidencia del pointcut. La expresión aquí execution(* com.example.demo.aop.MyService.performAction(..))significa que el punto de corte coincide con la ejecución del método MyServiceen la interfaz performAction, y el punto de corte se usa para especificar en qué puntos de conexión ( Join Pointcomo llamadas a métodos) se aplica la notificación.

Acerca del análisis de expresionesexecution(* com.example.demo.aop.MyService.performAction(..))

ejecución : es la función de punto de corte más utilizada, que se utiliza para hacer coincidir los puntos de conexión de la ejecución del método.

*: Indica que el tipo de retorno del método es arbitrario.

com.example.demo.aop.MyService.performAction : especifica la ruta completa del nombre de la interfaz y el nombre del método.

(…) : Indica que los parámetros del método son arbitrarios y coincidirán independientemente de cuántos parámetros tenga el método.

  • Punto de unión : un punto de unión se refiere a un punto determinado durante la ejecución del programa, como una llamada a un método. Los puntos de unión se identifican y coinciden  mediante expresiones pointcut ( ), que definen un pointcut que especifica un conjunto explícito de puntos de unión, es decir, todas las invocaciones de métodos de la interfaz . En este ejemplo, las llamadas al método de interfaz son puntos de conexión potenciales. Cada vez que se llama a un método, se alcanza un punto de unión . Este punto de conexión es donde se notifica a la aplicación su sincronización.Pointcutexecution(* com.example.demo.aop.MyService.performAction(..))MyServiceperformActionMyServiceperformActionperformAction

  • Consejo : Esta es una AOPacción que mejora la ejecución de un método al realizar acciones en momentos específicos. methodEl atributo especifica el nombre del método del aspecto que debe ejecutarse cuando el punto de corte coincide, pointcut-refhaciendo referencia al punto de corte definido anteriormente. Por ejemplo, aquí está el método que se llama antes de ejecutar beforeAdviceel método de destino . performActionEsto significa que siempre que MyService.performAction(..)se llame a un método, beforeAdviceel método se ejecutará primero.

Para resumir en una frase: Spring AOPal definir reglas (puntos de corte) en aspectos para especificar cuándo (puntos de conexión) y cómo (notificaciones) mejorar métodos específicos, se logra la modularización del código y la separación de preocupaciones sin modificar la lógica empresarial original. .

De esta manera, Spring AOP puede definir una lógica personalizada que se insertará antes, después o alrededor de la ejecución de un método específico sin modificar el código de lógica empresarial original. Este es un mecanismo poderoso para lograr la separación de inquietudes, especialmente para inquietudes transversales que abarcan múltiples partes de la aplicación (como el registro, la gestión de transacciones, etc.).

Tenga en cuenta que si <aop:config>se establece en

<aop:config proxy-target-class="true">
    <!--Otra configuración permanece sin cambios-->
</aop:config>

Configurar esto proxy-target-class="true"hará que el proxy Spring AOPse use con preferencia CGLIBincluso si el objeto de destino implementa la interfaz. De forma predeterminada, proxy-target-classno es necesario establecer la propiedad o, si se establece false, se utiliza un proxy dinámico JDK.

Programa principal:

Aplicación de demostración.java:

paquete com.ejemplo.demo;

importar com.example.demo.aop.MyService;
importar org.springframework.context.support.ClassPathXmlApplicationContext;

Aplicación de demostración de clase pública {
    público estático vacío principal (String [] argumentos) {
        Contexto ClassPathXmlApplicationContext = nuevo ClassPathXmlApplicationContext("applicationContext.xml");
        MiServicio miServicio = (MiServicio) context.getBean("miServicio");

        intentar {
            System.out.println(myService.performAction("normal"));
        } captura (Excepción e) {
            e.printStackTrace();
        }

        System.out.println("========================");

        intentar {
            System.out.println(myService.performAction("lanzar"));
        } captura (Excepción e) {
            System.out.println("Excepción detectada en principal: " + e.getMessage());
        }

        contexto.close();
    }
}

resultado de la operación:

Al combinar la tecnología de proxy dinámico con estos AOPconceptos, Spring AOPse puede proporcionar a las aplicaciones soporte para inquietudes transversales de una manera no intrusiva, lo que permite a los desarrolladores modularizar estas inquietudes y mantener los componentes de la lógica empresarial enfocados y simples.

Si está interesado en el proxy dinámico, puede depurarlo nuevamente. JDKEl proxy dinámico aquí se debe a que public class MyServiceImpl implements MyService la interfaz está implementada de la siguiente manera:

Hablemos brevemente sobre las clases e interfaces clave que se pueden ver aquí.

ProxyFactory : esta es Spring AOPuna clase de fábrica utilizada para crear objetos proxy. Puede decidir utilizar JDKproxy dinámico o proxy en función de si el objeto de destino implementa la interfaz CGLIB.

AopProxy : esta interfaz define métodos para obtener objetos proxy. Tiene dos implementaciones principales: JdkDynamicAopProxy(para JDKproxies dinámicos) y CglibAopProxy(para CGLIBproxies).

JdkDynamicAopProxy : implementa AopProxyla interfaz y utiliza JDKtecnología de proxy dinámico para crear un proxy. Implementa InvocationHandlerla interfaz e intercepta todas las llamadas a métodos del objeto proxy.

CglibAopProxy : también implementa AopProxyla interfaz, pero utiliza CGLIBuna biblioteca para crear objetos proxy. Para las clases que no implementan la interfaz, Springse elegirá este método para crear el proxy.

Si desea comprender Spring AOPel código fuente en profundidad, puede ver directamente JdkDynamicAopProxyla CglibAopProxyimplementación de estas dos clases. Este no es el enfoque de este artículo, solo mencione brevemente:

Por ejemplo, JdkDynamicAopProxyconsulte la implementación del proxy dinámico en:

  1. JdkDynamicAopProxyLas clases implementan InvocationHandlerinterfaces, que son JDKel núcleo del proxy dinámico. En su invokemétodo, habrá lógica para determinar si es necesario interceptar la llamada y se aplicarán las notificaciones correspondientes antes y después de la llamada.

  2. El proceso de creación de un proxy se realiza principalmente ProxyFactoryllamando createAopProxy()a un método, que devuelve una instancia de JdkDynamicAopProxyo según la configuración CglibAopProxy.

  3. Uso de proxy: el código del cliente ProxyFactoryobtiene el objeto proxy y llama al método de destino a través de este objeto proxy. El objeto proxy utiliza JdkDynamicAopProxyo internamente CglibAopProxypara interceptar estas llamadas y AOPrealizar notificaciones según la configuración. El proceso de obtención ProxyFactoryde un objeto proxy Springgeneralmente se realiza implícitamente en la configuración y el uso, especialmente cuando se usa Springla administración de contenedores AOP. Este proceso no requiere que el desarrollador llame ProxyFactorya la clase directamente. Cuando Springse define uno en la configuración beany se le aplica un aspecto, Springel contenedor maneja automáticamente el proceso de creación del agente y aplicación de notificaciones. Esto se logra mediante soporte Springde posprocesador y AOPespacio de nombres, y los desarrolladores generalmente solo necesitan configurar aspectos y consejos de forma declarativa.

Si quieres ver CGLIBal agente, aquí 2tienes una forma.

El tercer 1método es eliminar la interfaz MyServiceImplimplementada y luego cambiar el lugar correspondiente entre MyServiceel programa principal y la expresión . La tercera forma es establecer explícitamente las propiedades de la etiqueta en el archivo de configuración para lograrlo. como sigue:expressionMyServiceImpl
2Spring<aop:config>proxy-target-class="true"

<aop:config proxy-target-class="true">
    <!--Otra configuración permanece sin cambios-->
</aop:config>

La depuración es la siguiente:

 

Bienvenido a la conexión triple con un clic ~

Si tiene alguna pregunta, deje un mensaje y analicemos y aprendamos juntos.

Haga clic para seguir y conocer las nuevas tecnologías de Huawei Cloud lo antes posible ~

 

RustDesk suspendió el servicio doméstico Taobao (taobao.com) debido a un fraude desenfrenado, reinició el trabajo de optimización de la versión web, Apple lanzó el chip M4, los estudiantes de secundaria crearon su propio lenguaje de programación de código abierto como una ceremonia de mayoría de edad - Los internautas comentaron: Confiando en La defensa, Yunfeng renunció a Alibaba y planea producir en el futuro el destino para programadores de juegos independientes Visual Studio Code 1.89, según anunció oficialmente Huawei. El ajuste laboral de Yu Chengdong fue clavado en el “FFmpeg Pillar of Shame”. "Hace 15 años, pero hoy tiene que agradecernos: ¿Tencent QQ Video se venga de su vergüenza anterior? La estación espejo de código abierto de la Universidad de Ciencia y Tecnología de Huazhong está oficialmente abierta al acceso a la red externa
{{o.nombre}}
{{m.nombre}}

Supongo que te gusta

Origin my.oschina.net/u/4526289/blog/11106069
Recomendado
Clasificación