Análisis en profundidad del principio AOP del framework Spring

Spring AOP (programación orientada a aspectos) es un marco basado en la programación orientada a aspectos, que puede administrar múltiples objetos de destino de manera unificada y agregar funciones adicionales sin modificar el código comercial original. El proceso de implementación se basa principalmente en las tecnologías proxy (Proxy) y proxy dinámico (Dynamic Proxy).Este artículo analizará en detalle el principio de implementación de Spring AOP.

1. El concepto básico de AOP

AOP nos ayuda a definir mejor nuestra lógica comercial al descomponer una aplicación en sus partes importantes y luego separar las preocupaciones que abarcan esas partes. Entre ellos, los conceptos básicos incluyen:

  • Aspect (Aspect) El aspecto es el código funcional entretejido en la clase de destino.Para Java, puede ser el código en un punto específico de un método, constructor o clase. Los aspectos pueden incluir notificación previa, notificación posterior, notificación envolvente, notificación de excepción y notificación final, etc., que se pueden personalizar según las necesidades comerciales.

  • Punto de conexión (Join Point) El punto de conexión indica dónde se entretejerá el aspecto en el objeto de destino. Para Java, suele ser el punto de ejecución de un método o el punto de creación de un constructor.

  • Pointcut (Pointcut) Pointcut es una colección de puntos de conexión, que define qué puntos de conexión deben entretejerse en el objeto de destino.

  • Asesoramiento (Advice) El asesoramiento incluye varios tipos de códigos de aspecto, como el asesoramiento previo, el asesoramiento posterior, el asesoramiento envolvente, el asesoramiento de excepción y el asesoramiento final.

  • Tejer Tejer es el proceso de tejer el código de aspecto en el objeto de destino, lo que puede ocurrir en tiempo de compilación, tiempo de carga o tiempo de ejecución. Spring AOP utiliza la tecnología de proxy dinámico como método principal para tejer.

  • Introducción La introducción nos permite agregar nuevos métodos y propiedades a una clase existente que no están definidas en la definición de la clase original pero que están definidas en la interfaz importada.

Dos, tres formas de implementación de AOP

Antes de presentar el principio de implementación de Spring AOP, primero comprendemos las tres formas de implementar AOP: proxy estático, usar la clase Proxy de JDK para implementar un proxy dinámico y usar CGLIB para implementar un proxy dinámico.

Para comprender mejor el principio de implementación de Spring AOP y la forma en que AOP usa el proxy dinámico, podemos tener una comprensión profunda de tres formas: proxy estático, proxy dinámico JDK y proxy dinámico CGLIB.

1. Proxy estático

El proxy estático se refiere a que las clases y los métodos que deben ser enviados por proxy se determinaron en el momento de la compilación. La clase de proxy ya existe en el momento de la compilación. Su ventaja es la alta eficiencia operativa, pero su desventaja es que no es flexible y solo puede usar el proxy antes -clases y métodos definidos. El siguiente es un ejemplo simple para ilustrar el principio del proxy estático:

Primero defina una interfaz Asunto:

public interface Subject {
    void request();
}

A continuación, defina un objeto de destino RealSubject:

public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject is handling the request.");
    }
}

Finalmente defina un objeto proxy ProxySubject:

public class ProxySubject implements Subject {
    private Subject realSubject;

    public ProxySubject(Subject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public void request() {
        System.out.println("ProxySubject is handling the request.");
        realSubject.request();
    }
}

En el ejemplo anterior, ProxySubject es un objeto proxy que implementa la interfaz Subject, contiene un objeto real realSubject y agrega lógica de procesamiento adicional en el método request().

Cuando necesitamos llamar a un método en la interfaz de Asunto, podemos llamarlo creando un objeto proxy ProxySubject, de la siguiente manera:

public static void main(String[] args) {
    Subject subject = new RealSubject();
    subject.request();

    Subject proxySubject = new ProxySubject(subject);
    proxySubject.request();
}

Al ejecutar el programa, encontraremos la siguiente salida:

RealSubject is handling the request.
ProxySubject is handling the request.
RealSubject is handling the request.

En el ejemplo anterior, cuando el objeto proxy ProxySubject llama al método request(), primero imprime la oración "ProxySubject está manejando la solicitud" y luego llama al método request() del objeto de destino RealSubject.

2. Proxy dinámico JDK

El proxy dinámico de JDK hace referencia al proceso de generación dinámica de clases de proxy a través de la clase de proxy y la interfaz InvocationHandler que viene con Java. La clase de proxy generada dinámicamente en tiempo de ejecución puede implementar cualquier interfaz. En comparación con el proxy estático, es más flexible, pero solo puede ser implementado por proxy Una clase que tiene una interfaz no puede representar una clase que no implementa una interfaz. El siguiente es un ejemplo simple para ilustrar el principio del proxy dinámico JDK:

Primero defina una interfaz Asunto:

public interface Subject {
    void request();
}

A continuación, defina un objeto de destino RealSubject:

public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject is handling the request.");
    }
}

A continuación, defina una clase de implementación InvocationHandler MyInvocationHandler:

public class MyInvocationHandler implements InvocationHandler {
    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("ProxySubject is handling the request.");
        Object result = method.invoke(target, args);
        return result;
    }
}

En el ejemplo anterior, MyInvocationHandler implementa la interfaz InvocationHandler y reescribe el método de invocación(), agregando lógica de procesamiento adicional a este método.

Finalmente, cree un objeto proxy dinámico en el programa principal:

public static void main(String[] args) {
    Subject realSubject = new RealSubject();
    InvocationHandler invocationHandler = new MyInvocationHandler(realSubject);
    Subject proxySubject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), invocationHandler);
    proxySubject.request();
}

Al ejecutar el programa, encontraremos la siguiente salida:

ProxySubject is handling the request.
RealSubject is handling the request.

En el ejemplo anterior, el objeto proxy proxySubject se crea llamando al método Proxy.newProxyInstance(), que puede representar cualquier clase que implemente la interfaz Subject.

3. Proxy dinámico CGLIB

El proxy dinámico CGLIB se refiere al proceso de usar la biblioteca CGLIB para generar clases de proxy dinámicamente. A diferencia del proxy dinámico JDK, el proxy dinámico CGLIB puede representar clases que no implementan interfaces y tiene una aplicabilidad más amplia. El siguiente es un ejemplo simple para ilustrar el principio del proxy dinámico CGLIB:

Primero defina un objeto de destino RealSubject:

public class RealSubject {
    public void request() {
        System.out.println("RealSubject is handling the request.");
    }
}

Luego defina una clase de implementación de MethodInterceptor MyMethodInterceptor:

public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("ProxySubject is handling the request.");
        Object result = proxy.invokeSuper(obj, args);
        return result;
    }
}

En el ejemplo anterior, MyMethodInterceptor implementa la interfaz MethodInterceptor y reescribe el método intercept(), agregando lógica de procesamiento adicional a este método.

Finalmente, cree un objeto proxy dinámico en el programa principal:

public static void main(String[] args) {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(RealSubject.class);
    enhancer.setCallback(new MyMethodInterceptor());
    RealSubject proxySubject = (RealSubject) enhancer.create();
    proxySubject.request();
}

Al ejecutar el programa, encontraremos la siguiente salida:

ProxySubject is handling the request.
RealSubject is handling the request.

En el ejemplo anterior, el objeto proxy proxySubject se crea llamando al método Enhancer.create(), que puede representar cualquier clase, incluidas las clases que no implementan ninguna interfaz.

En términos generales, los proxies estáticos y los proxies dinámicos JDK se usan más ampliamente en estos tres métodos. Cuando los requisitos son relativamente simples y solo se necesita un pequeño número de interfaces o clases, se pueden seleccionar proxies estáticos y proxies dinámicos JDK; CGLIB dinámico Los proxies son relativamente más flexibles y pueden ser El proxy no implementa la clase de la interfaz, pero debido a que utiliza la biblioteca de operaciones de código de bytes ASM, es un poco menos eficiente que el proxy dinámico JDK. Por lo tanto, al elegir implementar AOP, es necesario elegir un método de implementación adecuado de acuerdo con las necesidades específicas .

Tres, principio de implementación de Spring AOP

Spring AOP se implementa principalmente a través de la API estándar proporcionada por AOP Alliance. Las interfaces principales incluyen:

  • Advisor Advisor es la clase básica de aspecto, que está asociada con Join Point y Advice, y solo necesita tratar con Advisor cuando llama externamente.

  • Pointcut Pointcut se usa para describir qué puntos de conexión en AOP deben entretejerse en el código de aspecto, y puede hacer coincidir los puntos de conexión de acuerdo con patrones denominados expresiones de punto de corte.

  • Consejo Consejo es la lógica específica del aspecto, que incluye Antes, Después de Regresar, Alrededor, Después de Tirar y Después.

  • JoinPoint JoinPoint representa un punto de conexión específico del objeto de destino, y la información sobre el punto de conexión se puede obtener en Consejos.

  • ProxyFactory ProxyFactory es una fábrica de proxy, que es responsable de crear objetos de proxy dinámicos y entrelazar aspectos en objetos de destino. Al mismo tiempo, se pueden agregar varios decoradores para lograr diferentes funciones.

A continuación, usamos un ejemplo simple para explicar en detalle el principio de implementación de Spring AOP.

Primero defina una clase de Persona:

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void say() {
        System.out.println("Hello, my name is " + name + ", I'm " + age + " years old.");
    }
}

Luego defina una clase de aspecto LogAspect:

public class LogAspect {
    public void before(JoinPoint joinPoint) {
        System.out.println("Method " + joinPoint.getSignature().getName() + " is invoked before...");
    }

    public void after(JoinPoint joinPoint) {
        System.out.println("Method " + joinPoint.getSignature().getName() + " is invoked after...");
    }
}

En el ejemplo anterior, LogAspect es una clase de aspecto, que incluye dos métodos de notificación antes y después.

Defina otra clase de prueba:

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person = (Person) context.getBean("person");
        person.say();
    }
}

Finalmente configure en applicationContext.xml:

<bean id="person" class="com.example.Person">
    <constructor-arg value="Tom"></constructor-arg>
    <constructor-arg value="18"></constructor-arg>
</bean>

<bean id="logAspect" class="com.example.LogAspect"></bean>

<aop:config>
    <aop:aspect id="log" ref="logAspect">
        <aop:before method="before" pointcut="execution(* com.example.Person.say(..))"></aop:before>
        <aop:after method="after" pointcut="execution(* com.example.Person.say(..))"></aop:after>
    </aop:aspect>
</aop:config>

Entre ellos, la etiqueta aop:config se usa para configurar el proxy AOP, la etiqueta aop:aspect se usa para configurar la información de aspecto, el atributo pointcut se usa para especificar el punto de entrada y el atributo de método se usa para especificar la notificación. método.

Al ejecutar el programa, encontraremos que se muestran los siguientes resultados:

Method say is invoked before...
Hello, my name is Tom, I'm 18 years old.
Method say is invoked after...

En el ejemplo anterior, el principio de implementación de Spring AOP incluye principalmente los siguientes pasos:

  • Analice la definición del bean según el archivo de configuración de Spring y cree el objeto Java Bean correspondiente.

  • Al crear un objeto Bean, si el objeto se declara como proxy, se creará un objeto proxy dinámico y se devolverá de acuerdo con todos los asesores definidos por el Bean.

  • En el proceso de creación de un objeto de proxy dinámico, Spring creará el código de bytes de la clase de proxy a través de bibliotecas propias o de terceros de JDK, como CGLIB, y lo cargará dinámicamente en la memoria de JVM.

  • Antes de llamar al método de destino, el objeto de proxy dinámico llamará primero a la lógica de aspecto correspondiente y luego llamará al propio método de destino.

  • Una vez que se ejecuta el método de destino, el objeto de proxy dinámico volverá a llamar a la lógica de aspecto correspondiente para completar todo el proceso de proxy.

Cuatro Resumen

Spring AOP es un marco de programación de aspectos basado en proxy y tecnología de proxy dinámico, que mejora la reutilización y el mantenimiento del código al descomponer la lógica empresarial en varias partes. En el proceso de implementación, Spring AOP administra y entreteje códigos de aspecto principalmente a través de interfaces centrales como Advisor, Pointcut, Advice, JoinPoint y ProxyFactory. Al usar Spring AOP, necesitamos definir clases de aspecto, unir puntos y puntos de corte, y especificar varios tipos de consejos a través de las etiquetas aop:config y aop:aspect en el archivo de configuración de Spring.

 

Supongo que te gusta

Origin blog.csdn.net/xxxzzzqqq_/article/details/130640995
Recomendado
Clasificación