Proceso de implementación de Spring AOP y análisis del código fuente

Prefacio

La interpretación literal de AOP es programación orientada a aspectos. La programación orientada a aspectos es un modelo de programación. Sabemos que JAVA está orientado a objetos, que es POO. La programación orientada a objetos de POO es adecuada para definir relaciones verticales, pero es no es adecuado para definir la relación horizontal. Entonces, para lidiar con estas desventajas de la existencia de esta POO, el modelo de programación orientado a aspectos AOP se utiliza como un complemento al orientado a objetos, que se usa para extraer y encapsular los comportamientos comunes y la lógica que no están relacionados con el negocio sino tienen un impacto en múltiples objetos Como módulo reutilizable, este módulo se denomina "Aspecto", lo que reduce el código repetitivo en el sistema, reduce el acoplamiento entre módulos y mejora la mantenibilidad del sistema. Se puede utilizar para la autenticación de autoridades, el registro y el procesamiento de transacciones.

Introducción al proxy AOP

Aquí está la implementación de AOP. Tenga en cuenta que no es Spring AOP. En primer lugar, la clave para la implementación de AOP radica en el modo proxy. El proxy AOP se divide en proxy dinámico y proxy estático. Como sabemos, Spring AOP pertenece a Dynamic proxy, y el representante de proxy estático es AspectJ;

Proxy estático

AspectJ es una mejora del proxy estático. El llamado proxy estático significa que el marco AOP generará clases de proxy AOP durante la fase de compilación, por lo que también es una mejora en tiempo de compilación. El proxy estático entrelazará AspectJ (aspectos) en el código de bytes de Java durante la fase de compilación. Cuando se ejecuta, es el objeto AOP mejorado;

Proxy dinámico

SpringAOP es un proxy dinámico. El llamado proxy dinámico significa que el marco AOP no modifica el archivo de código de bytes, sino que genera un objeto AOP para el método en tiempo cero en la memoria cada vez que se ejecuta. Este objeto AOP contiene todos los métodos del objeto de destino. Y procesamiento mejorado en aspectos específicos y métodos de devolución de llamada del objeto original;

la diferencia

La diferencia entre el proxy estático y el proxy dinámico es que el tiempo de generación de objetos proxy AOP es diferente. En comparación con el método proxy estático de AspectJ, tiene un mejor rendimiento, pero AspectJ requiere un compilador específico para su procesamiento, mientras que SpringAOP no requiere un compilador específico para proceso.

Proxy dinámico SpringAOP

Ya sabemos que SpringAOP se implementa mediante proxy dinámico En el proxy dinámico, hay dos métodos de implementación: proxy dinámico JDK y proxy dinámico CGLIB. Si la clase de proxy no implementa la interfaz InvocationHandler en el proxy dinámico JDK, SpringAOP elegirá usar CGLIB para proxy dinámicamente la clase de destino. Por defecto, @EnableAspectJAutoProxy no especifica proxyTargetClass = true (el valor predeterminado no está escrito como falso), y nuestra clase de negocios implementa la interfaz de la interfaz InvocationHandler, entonces AOP usará el proxy dinámico JDK, si no implementa la interfaz InvocationHandler, use el Proxy CGLIB, si @EnableAspectJAutoProxy tiene Specify proxyTargetClass = true, entonces es obligatorio usar CGLIB, independientemente de si la clase empresarial implementa la interfaz InvocationHandler o no, así como la mejora de referencia (se llama al método B en el método A) si exposeProxy = true se especifica en la anotación @EnableAspectJAutoProxy (el valor predeterminado es falso), luego el objeto proxy se expondrá a la variable del hilo, por lo que cuando llame, saque el objeto proxy de la variable del hilo y llámelo a través del objeto proxy, luego el ¡Se mejora un método y también se mejora el método B! Similar a la transacción A, el método llama al método de transacción B

  • El proxy dinámico JDK solo proporciona un proxy de interfaz y no es compatible con el proxy de clase. El núcleo es la clase Proxy. InvocationHandle llama al código en la clase de destino a través de la reflexión del método invoke (), tejiendo dinámicamente la lógica transversal y el negocio juntos; luego, Proxy usa InvocationHandle crea dinámicamente una instancia que se ajusta a una determinada interfaz para generar un objeto proxy de la clase de destino

  • CGLIB (Biblioteca de generación de código) es una biblioteca de clases para la generación de código, que puede generar dinámicamente un objeto de subclase de una clase específica en tiempo de ejecución, anular métodos específicos y agregar código mejorado para lograr AOP. CGLIB es un proxy dinámico de forma integrada, por lo que si una clase se marca como final, CGLIB no se puede utilizar como proxy dinámico.
    InvocationHandler

Terminología AOP

Joinpoint

Es un método que debe mejorarse

PointCut

Un conjunto de puntos de conexión se denomina punto tangente.

Aspecto

Es una clase que consta de puntos de corte, puntos de conexión y notificaciones.

Consejo

  • Notificación previa (antes): realice algunas operaciones antes de ejecutar el código comercial, como obtener el objeto de conexión
  • Después de la notificación (después): haga algo después de ejecutar el código comercial, se ejecutará independientemente de si se produce una excepción, como cerrar el objeto de conexión
  • Notificación de excepción (afterThrowing): la operación que debe realizarse cuando ocurre una excepción después de la ejecución del código comercial, como revertir la transacción
  • Notificación de devolución (afterReturning), la operación que se realizará sin excepción después de la ejecución del código comercial
  • Alrededor de la notificación (alrededor), no hay una operación correspondiente para la transacción de la que estamos hablando actualmente, por lo que no hablaré de eso por el momento.

Dirigirse a
los objetos comerciales que deben fortalecerse

Costura

Tejer es el proceso de agregar mejoras a puntos de conexión específicos a la clase objetivo. Tejer es un término vívido, específicamente, es el proceso de generar objetos proxy e integrar el contenido de los aspectos en los procesos comerciales.

Apoderado

Después de que AOP teje y mejora una clase, se crea una clase de proxy.

Código de ejemplo de SpringAOP

objetivo

@Service
public class A {
    
    
    public void f(){
    
    
        System.out.println("我被执行了");
    }
}

sección

@Component
@Aspect
public class MyAspect {
    
    
	
	//切点
    @Pointcut("execution(* com.xxx.xxx..*(..))")
    private void anyOldTransfcr(){
    
    }
	//com.xxx.xxx..*(..))这个中描述的每个方法为织入点

	//通知
    @Before("anyOldTransfcr()")
    public void advice(JoinPoint joinPoint){
    
    
        //String methodName=joinPoint.getSignature().getName();
        //System.out.println("执行的方法--->"+methodName);
        //System.out.println(Arrays.asList(joinPoint.getArgs()));
        System.out.println("--------开始执行-------");
    }

	//通知
    @After("anyOldTransfcr()")
    public void advice2(){
    
    
        System.out.println("--------结束执行-------");
    }

}

Clase de salida principal

@EnableAspectJAutoProxy(proxyTargetClass = true)

补充:这里在切面中有个@Aspect这个注解,和上面提到的AspectJ静态代理其实是有点关系的,因为Spring在刚开始实现AOP的时候写的语法是不太友好的,然后Spring后面在迭代的过程中实现AOP就参照了AspectJ的语法,注意是语法!

Ejecutar resultados después del inicio
Inserte la descripción de la imagen aquí

Análisis del proceso de implementación del código fuente de SpringAOP

Aquí debe pasar por todo el proceso de SpringIOC. Para decirlo sin rodeos, SpringAOP es una función implementada por una cierta parte de IOC. Para el proceso SpringIOC, consulte Análisis de código fuente de Spring ( combinación de procesos ). En este artículo, hay la siguiente imagen.
Inserte la descripción de la imagen aquí
El proceso de creación de objetos proxy de AOP se puede ver en la imagen de arriba. Se puede ver que está implementado en el proceso de creación de Bean El proceso AOP se divide en lo siguiente;

  1. Búsqueda de facetas
  2. Notificación de aspecto de caché
  3. Determine si el frijol actual pertenece al punto de tejido a través de la expresión pointcut
  4. Es el punto de tejido para crear un objeto proxy.
  5. Método de destino de ejecución

1. Búsqueda seccional

Cada vez que se crea un Bean, ingresará el método createBean en la clase AbstractAutowireCapableBeanFactory Hay un código muy clave sobre AOP en este método;
Inserte la descripción de la imagen aquí

		try {
    
    
			// 给BeanPostProcessors一个返回代理而不是目标bean实例的机会
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
    
    
				return bean;
			}
		}

Después de ingresar esta línea de código,
Inserte la descripción de la imagen aquí
continuar ingresando
Inserte la descripción de la imagen aquí
aquí es particularmente importante, cuando habilitamos la anotación de la función AOP, @EnableAspectJAutoProxy (proxyTargetClass = true)

Esta anotación nos ayudará a importar una clase AspectJAutoProxyRegistrar.
Inserte la descripción de la imagen aquí
Ingrese la clase AspectJAutoProxyRegistrar. Esta clase implementa la interfaz ImportBeanDefinitionRegistrar y reescribe las definiciones de registerBean. Así que definitivamente nos ayudará a registrar el Bean e ingrese este método para
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
registrar un AnnotationAwareAspectJAutoProxyCreator. ¡Sí, este frijol es muy importante!

Volver a nuestro código de proceso AOP

Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);

Esta línea de código ingresa a postProcessBeforeInstantiation en la clase AbstractAutoProxyCreator cuando ibp es el AnnotationAwareAspectJAutoProxyCreator inyectado arriba, porque el nivel superior de AnnotationAwareAspectJAutoProxyCreator hereda AbstractAutoProxyCreator, por lo que puede llamar al método postProcessBeforexy en la clase AbstractAutoxy.
Inserte la descripción de la imagen aquí
Este método shouldSkip (beanClass, beanName) llamará al método shouldSkip en la clase AspectJAwareAdvisorAutoProxyCreator. La
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
llamada aquí irá a buildAspectJAdvisors en la clase BeanFactoryAspectJAdvisorsBuilder. Este método es para encontrar la clase de aspecto y luego devolver el conjunto de tipos de notificación declarado en la clase de aspecto. .

2. Notificación de aspecto de la caché

List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);

En esta línea de código, se genera una colección de objetos de tipo notificación, y la clase de aspecto se usa como clave, y la colección de objetos de notificación se almacena como el valor de la clase de aspecto actual como clave.
Inserte la descripción de la imagen aquí
En este paso, el proceso de obtener la clase de aspecto y generar el objeto de notificación de acuerdo con la notificación en la clase de aspecto lleva mucho tiempo, por lo que el objeto de notificación analizado se agrega a la caché. Cuando la creación posterior del Bean llega aquí, primero determinará si el aspectoBeanNames está vacío. Si está vacío, simplemente busque los datos en el caché y regrese

Según el tipo de notificación en la clase de aspecto, la
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory); línea de código que genera el objeto de notificación se usa como entrada y finalmente ingresa el método getAdvice en la clase ReflectiveAspectJAdvisorFactory
Inserte la descripción de la imagen aquí

De regreso al proceso principal, luego el proceso principal ha encontrado la clase de aspecto y el objeto de notificación se ha almacenado en caché aquí, luego comience de la manera original y regrese al
Inserte la descripción de la imagen aquí
proceso principal y comience a ingresar al proceso de creación de Bean;
Inserte la descripción de la imagen aquí
omitimos el proceso de Asignación de atributos, mira, y AOP no importa mucho, directamente en el proceso de inicialización de Bean
Inserte la descripción de la imagen aquí
después de que se complete la inicialización se realizará
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
aquí, hay una clave, abierta aquí después de @EnableAspectJAutoProxy comentario AOP mencionado anteriormente BeanPostProcessor será más un AnnotationAwareAspectJAutoProxyCreator
Inserte la descripción de la imagen aquí
cuando el procesador aquí Cuando sea el objeto AnnotationAwareAspectJAutoProxyCreator, ingrese el método postProcessAfterInitialization en la clase AbstractAutoProxyCreator.
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Esta línea de código irá a 1. Busque la clase de aspecto, 2. Guarde en caché el objeto de notificación en la clase de aspecto, pero solo haga esta operación, pero el La primera vez que se llama al método shouldSkip ya es Después de completar las dos operaciones de 1. Busque la clase de aspecto y 2. Guarde en caché el objeto de notificación en la clase de aspecto, entonces la lógica no se ejecutará nuevamente aquí, pero después de ingresar a buildAspectJAdvisors () , volverá directamente a la primera ejecución de buildAspectJAdvisors () ¡El conjunto de resultados del objeto de notificación almacenado en caché por el método!

3. Determine si el frijol actual pertenece al punto de tejido mediante la expresión pointcut

Inserte la descripción de la imagen aquí
Si el valor devuelto es nulo, significa que el bean que debe inicializarse no necesita crear un objeto proxy. Si la devolución no es nula, entonces comience a crear un objeto proxy

4. ¿Es el punto de unión para crear un objeto proxy?

Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Use CGLIB para generar objetos proxy LaInserte la descripción de la imagen aquí
introducción de Spring AOP al principio del artículo explica por qué CGLIB se usa para completar el proxy dinámico.

5. Implementación del método objetivo

Inserte la descripción de la imagen aquí
Cuando se llama al método f, es el método f el que ingresa al objeto proxy.
Inserte la descripción de la imagen aquí
Dado que el CGLIB se utiliza para completar el proxy dinámico, la ejecución también es completada por el ejecutor del objeto proxy de apoyo. El CGLIB lo realiza CglibAopProxy y el ¡JDK lo realiza JdkDynamicAopProxy! De hecho, ¡finalmente se ejecuta a través del método continue () en la clase ReflectiveMethodInvocation!
Inserte la descripción de la imagen aquí

//当前拦截器的的索引
this.currentInterceptorIndex

//拦截器集合
this.interceptorsAndDynamicMethodMatchers

//当拦截器索引等于拦截器集合数组长度-1时,执行目标方法
this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1

//执行目标方法
return invokeJoinpoint();

//完成当前拦截器获取和当前拦截器索引++操作
Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

//使用当前索引获取到的拦截器执行invoke方法逻辑
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);

这里在invoke方法中传入的是this就是为了递归循环调用proceed()方法自己

Inserte la descripción de la imagen aquí
Cada recursividad agrega un bloque de código lógico al bloque de código y luego lo ejecuta. El código esqueleto recursivo completo es el anterior. ¡Ejecuta de arriba a abajo!

  1. AOP Aronud antes ...
  2. AOP antes del asesoramiento ...
  3. El método de destino se ejecuta ...
  4. AOP Aronud después de…
  5. AOP después del asesoramiento ...
  6. AOP AfterReturning Advice: (Si se completa la ejecución normal, ejecute el método actual)
  7. AOP AfterThrowing Advice ... (Si se lanza una excepción, se ejecuta el método actual)

Este flujo de llamadas se completa con la cadena de responsabilidad + recursividad

Supongo que te gusta

Origin blog.csdn.net/CSDN877425287/article/details/114328007
Recomendado
Clasificación