Operación AOP basada en AspectJ

Prefacio: AspectJ no es parte del marco Spring, sino un marco AOP independiente. Generalmente, los marcos AspectJ y Spirng se usan juntos para operaciones AOP

1. Términos relacionados con AOP

Por ejemplo, existen los siguientes 4 métodos en una clase:

Class A{
    
    
	add();
	delete();
	update();
	select();
}

1. Punto de conexión (JoinPoint)

Los 4 métodos de la clase A pueden mejorarse y estos 4 métodos se convierten en puntos de conexión.

2. Punto de entrada (PointCut)

Si en realidad solo mejoro los métodos add () y update (), entonces add () y update () se denominan puntos de entrada;
es decir, el método está realmente mejorado

3. Notificación y mejora (asesoramiento)

Por ejemplo, mejoro el método add () y agrego el código de juicio antes de la ejecución del método add (). Este código de juicio se llama notificación;
es decir, la parte lógica de la mejora real se llama notificación o mejora

Cinco tipos de notificaciones:

  • Notificación previa: hay algunas partes lógicas antes de que se ejecute el método add ()
  • Notificación posterior (notificación de devolución): hay algunas partes lógicas después de que se ejecuta el método add ()
  • Notificación envolvente: hay algunas partes lógicas antes y después de que se ejecute el método add ()
  • Notificación de excepción: la parte lógica que se ejecutará cuando ocurra una excepción en la ejecución del método add ()
  • Aviso final: similar al finalmente en try-catch-finalmente, la parte lógica que se ejecutará eventualmente

4.Aspecto

Un aspecto es una acción, y el proceso de aplicar nuestra notificación a un punto de entrada se llama aspecto.
Por ejemplo, el proceso de agregar el código de juicio al método add () se llama aspecto.


2. Expresión de punto de entrada

La función de la expresión pointcut es saber qué método en qué clase mejorar.

1. El formato de la expresión del punto de entrada

ejecución ([Modificador de permiso] [Tipo de valor de retorno] [Ruta de acceso completa de la clase] [Nombre del método] ([Lista de parámetros]) [Excepción])
El tipo de valor de retorno, el nombre del método y la lista de parámetros son obligatorios.

2. Comodín de expresión de corte de punto:

  1. *: coincide con todos los caracteres
  2. …: Generalmente se utiliza para hacer coincidir varios paquetes y varios parámetros
  3. +: indica la clase y sus subclases

Ejemplo 1: Mejorar la ejecución del método eat en la clase aop.annotation.Student (public void aop.annotation.Student.eat (...))
Ejemplo 2: Mejorar todos los métodos en la ejecución de la clase aop.annotation.Student ( * aop.annotation.Student. * (…))
Ejemplo 3: Para todas las clases y todos los métodos en el paquete aop.annotation, mejore la ejecución (* aop.annotation .. (…))

3. Ejemplo de código:

Clase StudentProxy:

@Component
@Aspect
public class StudentProxy {
    
    
    
    //前置通知
    @Before(value = "execution(public void aop.annotation.Student.eat(..))")
    public void beforeDemo(){
    
    
        System.out.println("饿了!");
    }

    //后置通知(返回通知)
    @AfterReturning("execution(* aop.annotation.Student.*(..))")
    public void afterReturningDemo(){
    
    
        System.out.println("饭后甜点");
    }

    //最终通知
    @After(value = "execution(void aop.annotation.Student.eat(..))")
    public void afterDemo(){
    
    
        System.out.println("饱了!");
    }

    //异常通知
    @AfterThrowing("execution(void aop.annotation.Student.eat(..))")
    public void afterThrowingDemo(){
    
    
        System.out.println("噎住了!");
    }

    //环绕通知
    @Around("execution(* aop.annotation.Student.*(..))")
    public void aroundDemo(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    
    
        System.out.println("吃饭前...");

        //被增强的方法执行
        proceedingJoinPoint.proceed();

        System.out.println("吃饭后...");

    }

}

Clase de estudiante:

@Component
public class Student {
    
    
    public void eat(){
    
    
        System.out.println("eat something!");
    }
}

archivo de configuración xml:

<?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:context="http://www.springframework.org/schema/context"
       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/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">


    <!--开启注解扫描-->
    <context:component-scan base-package="aop.annotation"></context:component-scan>

    <!--开启Aspect生成代理对象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

Categoría de prueba:

public class DemoTest {
    
    
    @Test
    public void test1(){
    
    
        ApplicationContext context = new ClassPathXmlApplicationContext("aop/annotation/bean.xml");

        Student student = context.getBean("student", Student.class);

        student.eat();
    }
}

Resultado de salida:

吃饭前...
饿了!
eat something!
饭后甜点
饱了!
吃饭后...

Process finished with exit code 0

Cambie el código en Student para informar un error de la siguiente manera:

@Component
public class Student {
    
    
    public void eat(){
    
    
        int i = 1/0;
        System.out.println("eat something!");
    }
}

Resultado de salida:
Inserte la descripción de la imagen aquí

4. Extraer del mismo punto de entrada

Utilice la anotación @Pointcut en el método pointDemo para reemplazar la expresión del punto de entrada de la notificación previa en el código anterior con el método pointDemo; de la
misma manera, se pueden reemplazar otras expresiones del punto de entrada para facilitar el desarrollo.


    //相同切入点抽取
    @Pointcut(value = "execution(* aop.annotation.Student.eat(..))")
    public void pointDemo(){
    
    

    }
    
    //前置通知
    @Before(value = "pointDemo()")
    public void beforeDemo(){
    
    
        System.out.println("饿了!");
    }

5.Anotación @ Order (valor de tipo de número)

Cuando hay varias clases de mejora para mejorar el mismo método, puede usar la anotación @Order (valor de tipo de número) para establecer la prioridad. Cuanto menor sea el valor de tipo de número, mayor será la prioridad, más prioridad se ejecutará.
Cree una clase StudentOneProxy para mejorar el método eat en la clase Student, establezca @Order (2), StudentOneProxy es el siguiente:

@Component
@Aspect
@Order(2)
public class StudentOneProxy {
    
    

    @Before("execution(* aop.annotation.Student.eat(..))")
    public void BeforeDemo(){
    
    
        System.out.println("StudentOneProxy.BeforeDemo...");
    }

    @Around("execution(* aop.annotation.Student.eat(..))")
    public void aroundDemo(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    
    
        System.out.println("StudentOneProxy.Around...");

        proceedingJoinPoint.proceed();

        System.out.println("StudentOneProxy.Around...");

    }
}

Agregue la anotación @Order (1) en la clase StudentProxy, la captura de pantalla es la siguiente:
Inserte la descripción de la imagen aquí
Resultado de salida:

吃饭前...
饿了!
StudentOneProxy.Around...
StudentOneProxy.BeforeDemo...
eat something!
StudentOneProxy.Around...
饭后甜点
饱了!
吃饭后...

Process finished with exit code 0

Puede ver que la clase Student establecida en @Order (1) se ejecuta primero.

Supongo que te gusta

Origin blog.csdn.net/MrYushiwen/article/details/111736821
Recomendado
Clasificación