Spring usa AspectJ para desarrollar AOP: basado en XML y basado en anotaciones

AspectJ es un marco AOP basado en el lenguaje Java, que extiende el lenguaje Java. Después de Spring 2.0, se agregó soporte para el modo AspectJ. Para la nueva versión de Spring Framework, se recomienda usar el modo AspectJ para desarrollar AOP.

Por lo general, hay dos formas de desarrollar AOP utilizando AspectJ:

  • Declarativo basado en XML.
  • Declarativo basado en anotación.


A continuación, explicaremos estos dos métodos de desarrollo de AOP.

Declarativo basado en XML

La declaración declarativa basada en XML significa definir aspectos, puntos de entrada y notificaciones de declaración a través de los archivos de configuración de Spring, y todos los aspectos y notificaciones deben definirse en el elemento <aop: config>.

El siguiente ejemplo muestra cómo usar la implementación declarativa basada en XML del desarrollo de AOP en Spring.

1. Importar el paquete JAR

Uso de AspectJ Además de importar el paquete Spring AOP JAR, también debe importar el paquete JAR relacionado con AspectJ, de la siguiente manera.

  • spring-aspectos-3.2.13.RELEASE.jar: La implementación que Spring proporciona para AspectJ ya se proporciona en el paquete Spring.
  • com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar: es una especificación proporcionada por AspectJ, puede  buscar y descargar en el sitio web oficial  https://repo.spring.io/webapp/#/search/quick/ .

2. Cree la clase de aspecto MyAspect

Cree un paquete llamado com.mengma.aspectj.xml en el directorio src, cree la clase de aspecto MyAspect debajo del paquete y edítelo de la siguiente manera.

package com.mengma.aspectj.xml;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
//切面类
public class MyAspect {
    // 前置通知
    public void myBefore(JoinPoint joinPoint) {
        System.out.print("前置通知,目标:");
        System.out.print(joinPoint.getTarget() + "方法名称:");
        System.out.println(joinPoint.getSignature().getName());
    }
    // 后置通知
    public void myAfterReturning(JoinPoint joinPoint) {
        System.out.print("后置通知,方法名称:" + joinPoint.getSignature().getName());
    }
    // 环绕通知
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint)
            throws Throwable {
        System.out.println("环绕开始"); // 开始
        Object obj = proceedingJoinPoint.proceed(); // 执行当前目标方法
        System.out.println("环绕结束"); // 结束
        return obj;
    }
    // 异常通知
    public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
        System.out.println("异常通知" + "出错了" + e.getMessage());
    }
    // 最终通知
    public void myAfter() {
        System.out.println("最终通知");
    }
}

En el código anterior, se definen varios métodos de tipo de notificación diferentes: en estos métodos, el nombre de clase, el nombre del método de destino y los parámetros del método de destino del objeto de destino se pueden obtener a través del parámetro JoinPoint. Debe tenerse en cuenta que la notificación envolvente debe recibir un parámetro de tipo ProceedingJoinPoint, el valor de retorno debe ser de tipo Objeto y se debe lanzar una excepción. Los parámetros de tipo arrojables se pueden pasar a la notificación de excepción para generar información de excepción.

3. Crear un archivo de configuración de Spring

Cree un archivo de configuración para applicationContext.xml en el paquete com.mengma.aspectj.xml, como se muestra a continuación. 

<?xml version="1.0" encoding="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-2.5.xsd  
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
    <!--目标类 -->
    <bean id="customerDao" class="com.mengma.dao.CustomerDaoImpl" />
    <!--切面类 -->
    <bean id="myAspect" class="com.mengma.aspectj.xml.MyAspect"></bean>
    <!--AOP 编程 -->
    <aop:config>
        <aop:aspect ref="myAspect">
            <!-- 配置切入点,通知最后增强哪些方法 -->
            <aop:pointcut expression="execution ( * com.mengma.dao.*.* (..))"
                id="myPointCut" />
            <!--前置通知,关联通知 Advice和切入点PointCut -->
            <aop:before method="myBefore" pointeut-ref="myPointCut" />
            <!--后置通知,在方法返回之后执行,就可以获得返回值returning 属性 -->
            <aop:after-returning method="myAfterReturning"
                pointcut-ref="myPointCut" returning="returnVal" />
            <!--环绕通知 -->
            <aop:around method="myAround" pointcut-ref="myPointCut" />
            <!--抛出通知:用于处理程序发生异常,可以接收当前方法产生的异常 -->
            <!-- *注意:如果程序没有异常,则不会执行增强 -->
            <!-- * throwing属性:用于设置通知第二个参数的名称,类型Throwable -->
            <aop:after-throwing method="myAfterThrowing"
                pointcut-ref="myPointCut" throwing="e" />
            <!--最终通知:无论程序发生任何事情,都将执行 -->
            <aop:after method="myAfter" pointcut-ref="myPointCut" />
        </aop:aspect>
    </aop:config>
</beans>

En el código anterior, en primer lugar, el espacio de nombres AOP se importa en las líneas de código 4, 7 y 8. El código de la línea 12 especifica la clase de aspecto.

Las líneas 17 y 18 configuran el punto de entrada y notifican qué métodos deben mejorarse. Expression = "ejecución (* com.mengma.dao. *. * (..)) significa mejorar todos los paquetes com.mengma.dao. Método: las

líneas 20 a 32 se usan para asociar notificaciones (consejos) y puntos de corte (PointCut). Tomando la notificación previa en la línea 20 como ejemplo, el atributo del método de la etiqueta <aop: before> se usa para especificar notificaciones, pointcut-ref El atributo se utiliza para especificar el punto de entrada, que es el método a mejorar. Para la configuración de varias otras notificaciones, puede consultar los comentarios del código.

4. Crear una clase de prueba

Cree una clase de prueba XMLTest bajo el paquete com.mengma.aspectj.xml, como se muestra a continuación. 

package com.mengma.aspectj.xml;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mengma.dao.CustomerDao;
public class XMLTest {
    @Test
    public void test() {
        String xmlPath = "com/mengma/aspectj/xml/applicationContext.xml";
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                xmlPath);
        // 从spring容器获取实例
        CustomerDao customerDao = (CustomerDao) applicationContext
                .getBean("customerDao");
        // 执行方法
        customerDao.add();
    }
}

5. Ejecute el proyecto y vea los resultados.

Use la prueba JUnit para ejecutar el método test (). Después de una operación exitosa, la salida de la consola se muestra en la Figura 1.
 

Resultado de la operación
Figura 1 resultados corrientes


Para demostrar mejor la notificación de excepción, a continuación, agregue una línea de código que arroje una excepción en el método add () de la clase CustomerDaoImpl, como "int i = 1/0;", vuelva a ejecutar la clase de prueba XMLTest, puede ver la notificación de excepción Ejecutado, y la salida de la consola se muestra en la Figura 2.
 

Resultado de la operación
Figura 2 resultados corrientes


Se puede ver a partir de los resultados de la Figura 1 y la Figura 2 que el desarrollo de AOP declarativo basado en XML se ha implementado con éxito.

Declarativo basado en anotaciones

En Spring, aunque los archivos de configuración XML se pueden usar para implementar el desarrollo de AOP, si todas las configuraciones relacionadas se concentran en los archivos de configuración, inevitablemente hará que los archivos de configuración XML estén demasiado hinchados, lo que traerá ciertas dificultades para el mantenimiento y la actualización.

Por esta razón, el marco de AspectJ proporciona otro método de desarrollo para el desarrollo de declaración de AOP basado en Anotación. AspectJ permite que las anotaciones definan aspectos, puntos de entrada y procesamiento mejorado, y Spring Framework puede reconocer y generar proxys AOP basados ​​en estas anotaciones.

La introducción de las anotaciones de Anotación se muestra en la Tabla 1.

El nombre Explicación
@Aspecto Se usa para definir un segmento.
@Antes de Se usa para definir pre-asesoramiento, equivalente a BeforeAdvice.
@AfterReturning Se utiliza para definir la notificación posterior, equivalente a AfterReturningAdvice.
@Alrededor Se utiliza para definir la notificación envolvente, equivalente a MethodInterceptor.
@AfterThrowing Se utiliza para definir la notificación de lanzamiento, equivalente a ThrowAdvice.
@Después Se utiliza para definir la notificación final, ya sea anormal o no, la notificación se ejecutará.
@DeclareParents Se usa para definir la notificación de introducción, equivalente a IntroductionInterceptor (no se requiere masterización).

A continuación se utilizan anotaciones para volver a implementar las funciones de la parte "declarativa basada en XML".

1. Crear una sección MyAspect

Cree un paquete llamado com.mengma.aspectj.annotation en el directorio src y cree una clase de faceta MyAspect en este paquete, como se muestra a continuación. 

package com.mengma.aspectj.annotation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
//切面类
@Aspect
@Component
public class MyAspect {
    // 用于取代:<aop:pointcut
    // expression="execution(*com.mengma.dao..*.*(..))" id="myPointCut"/>
    // 要求:方法必须是private,没有值,名称自定义,没有参数
    @Pointcut("execution(*com.mengma.dao..*.*(..))")
    private void myPointCut() {
    }
    // 前置通知
    @Before("myPointCut()")
    public void myBefore(JoinPoint joinPoint) {
        System.out.print("前置通知,目标:");
        System.out.print(joinPoint.getTarget() + "方法名称:");
        System.out.println(joinPoint.getSignature().getName());
    }
    // 后置通知
    @AfterReturning(value = "myPointCut()")
    public void myAfterReturning(JoinPoint joinPoint) {
        System.out.print("后置通知,方法名称:" + joinPoint.getSignature().getName());
    }
    // 环绕通知
    @Around("myPointCut()")
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint)
            throws Throwable {
        System.out.println("环绕开始"); // 开始
        Object obj = proceedingJoinPoint.proceed(); // 执行当前目标方法
        System.out.println("环绕结束"); // 结束
        return obj;
    }
    // 异常通知
    @AfterThrowing(value = "myPointCut()", throwing = "e")
    public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
        System.out.println("异常通知" + "出错了" + e.getMessage());
    }
    // 最终通知
    @After("myPointCut()")
    public void myAfter() {
        System.out.println("最终通知");
    }
}

En el código anterior, la anotación @Aspect en la línea 13 se usa para declarar que esta es una clase de aspecto, que se usa como un componente, por lo que debe agregar la anotación @Component para que surta efecto. La anotación @Poincut en la línea 19 se usa para configurar el punto de corte, reemplazando el código para configurar el punto de corte en el archivo XML.

Las anotaciones se agregan al método correspondiente de cada notificación y el nombre del método de corte de puntos "myPointCut" se pasa como un parámetro al método que se ejecutará. Si se requieren otros parámetros (como parámetros de excepción para notificación de excepción), se pueden pasar de acuerdo con la solicitud de código El valor del atributo correspondiente.

2. Anota la clase objetivo

Agregue la anotación @Repository ("customerDao") en la clase de destino com.mengma.dao.CustomerDaoImpl.

3. Crear un archivo de configuración de Spring

Cree el archivo de configuración applicationContext.xml en el paquete com.mengma.aspectj.annotation, como se muestra a continuación.

<?xml version="1.0" encoding="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"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    <!--扫描含com.mengma包下的所有注解-->
    <context:component-scan base-package="com.mengma"/>
    <!-- 使切面开启自动代理 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

En el código anterior, el espacio de nombres AOP y sus restricciones de soporte se importan primero para que la anotación @AspectJ en la clase de aspecto funcione correctamente; el paquete de escaneo se agrega en la línea 13 para que la anotación sea efectiva. Cabe señalar que aquí también se incluye la anotación de la clase objetivo com.mengma.dao.CustomerDaoImpl, por lo que el valor del paquete base es com.mengma; la función de la línea 15 del código es abrir el proxy automático en el aspecto.

4. Crear una clase de prueba

Cree una clase de prueba llamada AnnotationTest en el paquete com.mengma.aspectj.annotation, como se muestra a continuación. 

package com.mengma.aspectj.annotation;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mengma.dao.CustomerDao;
public class AnnotationTest {
    @Test
    public void test() {
        String xmlPath = "com/mengma/aspectj/xml/applicationContext.xml";
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                xmlPath);
        // 从spring容器获取实例
        CustomerDao customerDao = (CustomerDao) applicationContext
                .getBean("customerDao");
        // 执行方法
        customerDao.add();
    }
}

5. Ejecute el proyecto y vea los resultados.

Use la prueba JUnit para ejecutar el método test (). Después de una operación exitosa, la salida de la consola se muestra en la Figura 3.
 

Resultado de la operación
Figura 3 resultados corrientes


Elimine "int i = 1/0;" en el método add () y vuelva a ejecutar el método test (). En este momento, la salida de la consola se muestra en la Figura 4.
 

Resultado de la operación
Figura 4 resultados corrientes


Como se puede ver en los resultados de salida de la Figura 3 y la Figura 4, el desarrollo de AOP se ha implementado con éxito usando Anotación. En comparación con otros métodos, es la forma más conveniente de lograr el efecto de AOP basado en Anotación, por lo que se recomienda usar anotaciones en el desarrollo real.

Publicados 203 artículos originales · ganado elogios 6 · vistas 4499

Supongo que te gusta

Origin blog.csdn.net/weixin_42073629/article/details/105236512
Recomendado
Clasificación