Me encontré con un entrevistador "maravilloso" que me criticó Spring AOP y me pidió que vomitara

Preste atención, no se pierda; continúe actualizando las tecnologías y la información relacionadas con Java. ! !
No show talk hoy.

¿Qué es AOP?

El nombre completo de AOP es Programación Orientada a Aspectos, que se traduce como "Programación Orientada a Aspectos". En el lenguaje Java, todo es un objeto, por lo que solemos decir que el lenguaje Java es un lenguaje de programación "orientado a objetos". Y la programación orientada a aspectos no reemplaza la programación orientada a objetos, sino que la complementa.
El problema que debe resolver AOP es utilizar un enfoque "transversal" para manejar uniformemente las mismas funciones o funciones similares requeridas por muchos objetos, reducir el código repetitivo en el programa y hacer que el código sea más limpio y más centrado en los negocios.

Inserte la descripción de la imagen aquí

¿Qué puede hacer AOP?

AOP es adecuado para hacer cosas que son más generales y tienen poco que ver con los negocios. Los más comunes son los registros de llamadas, el control de permisos, el tiempo de llamada y las estadísticas de rendimiento, la verificación de parámetros, etc.

De hecho, Spring ha hecho muchas cosas útiles basadas en AOP, como transacciones, almacenamiento en caché, reintento, validación, etc. que puede usar con frecuencia. La capa inferior es AOP.

También hay más requisitos para implementar algunas funciones pequeñas con AOP. Por ejemplo, nuestro equipo tenía tal requisito antes, no usamos enumeraciones para las llamadas entre servicios, sino que las reemplazamos con cadenas, es decir, enumeramos los nombres de los campos correspondientes. Pero esto genera un problema, si la persona que llama ingresa una cadena que no pertenece a esta enumeración, lanzará una excepción cuando se use más adelante. Así que esperamos poder hacer esta verificación en la capa Controlador y lanzar una excepción.

Este es un requisito para la verificación de parámetros. Sin embargo, ni la Validación proporcionada por Spring ni la Validación personalizada pueden cumplir con este requisito, porque el campo es una cadena, pero el tipo de enumeración que debe verificarse cada vez es diferente. Así que desarrollamos un validador de parámetros de enumeración basado en anotaciones y AOP.

¿Cuál es la relación entre Spring AOP y AspectJ?

De hecho, AOP no es exclusivo de Spring, originalmente AOP era un modelo de programación, posteriormente, para discutir la estandarización de AOP y unificar la especificación de AOP, establecieron una alianza AOP. Además de Spring, hay muchos marcos AOP, como AspectJ, AspectWerkz, JBoss-AOP.

Inicialmente, Spring AOP y AspectJ son completamente independientes, y Spring tiene su propia implementación y sintaxis de uso. Pero el AOP de Spring es demasiado complicado de usar y todos se quejan. Por lo tanto, Spring admite la sintaxis de AspectJ ampliamente aclamada, agregando la anotación @EnableAspectJAutoProxy a la clase de configuración para habilitar la sintaxis de AspectJ.

Pero Spring "solo admite parte de la sintaxis de AspectJ (parte de la sintaxis no es compatible), pero la implementación subyacente sigue siendo su propio conjunto de cosas". Además, los objetivos de los dos marcos son diferentes: AspectJ es una solución AOP completa, que es más robusta, pero más complicada de usar y requiere una sintaxis y compiladores especiales. El propósito de Spring es combinar los marcos AOP e IoC para que los Beans administrados por Spring puedan usar fácilmente las funciones AOP.

Así que Spring AOP no tiene nada que ver con AspectJ, pero Spring toma prestado de la sintaxis de declaración de Aspect.

Aquí hay una descripción clara de la relación entre AOP, Spring AOP, AspectJ, luego usaré AOP en lugar de Spring AOP a continuación, después de todo, este es un autor relativamente vago.

¿Cómo usar Spring AOP?

Para aprender una tecnología, primero debe aprender a usarla, luego aprender los principios y finalmente pensar profundamente y hacer inferencias unos de otros. Y "la mejor forma de aprender a utilizarlo es leer la documentación oficial".

Algunos estudiantes pueden encontrar que el inglés no es conveniente, por lo que leerán algunos artículos o libros chinos. Pero estos artículos o libros chinos son en realidad documentos oficiales traducidos y pueden estar incompletos o incluso incorrectos. Por lo tanto, se recomienda leer los documentos oficiales directamente, incluso si usa un software de traducción automática, puede comprenderlo. Además, el inglés puede considerarse una de las habilidades necesarias para los programadores.

Inserte la descripción de la imagen aquí
AOP tiene algunos conceptos y terminología profesionales. Aspectos, puntos de conexión, notificaciones, puntos de corte, introducciones, objetos de destino, objetos de proxy, tejido, etc. Muchos de ellos están traducidos directamente en base a palabras en inglés. No presentaremos estos conceptos en detalle aquí. Hay una introducción detallada al comienzo del capítulo AOP del documento oficial de Spring. Pero este artículo presentará algunos de estos términos desde la perspectiva del uso.

Activa la compatibilidad con AspectJ

Este artículo no presentará la configuración de XML, es demasiado antiguo. . .

Use la anotación @EnableAspectJAutoProxy para habilitar la compatibilidad con AspectJ, y podrá usar la sintaxis de AspectJ en Spring en el futuro. Cabe señalar que "si está utilizando SpringBoot, esta anotación se ha agregado de forma predeterminada", no es necesario que la escriba en su código manualmente.

Declara un aspecto

Utilice la anotación @Aspect para declarar un aspecto. De hecho, es una clase, en la que se definen cortes de puntos, notificaciones y otras cosas.

Declarar un pointcut

El llamado "punto de corte" es donde se va a cortar. Spring solo admite el corte de "métodos de frijoles administrados por Spring". También es muy simple declarar un pointcut. En la clase de aspecto que declaramos arriba, simplemente crea un método en la siguiente forma:

@Pointcut("execution(* transfer(..))")
private void anyOldTransfer() {
    
    }

Utilice la anotación @Pointcut, que es la expresión del punto tangente. Tenga en cuenta que el valor de retorno de este método debe ser nulo. Con respecto a las expresiones, hay algunas palabras clave admitidas por Spring, que no se discutirán en detalle aquí. La sección Designadores de puntos de acceso admitidos en el documento oficial tiene una introducción detallada. Los dos más utilizados deberían ser ejecución y @anotación.
También hay algunos caracteres comodín, incluidos *,., (), (...), ( ), ( , cadena), etc., que tienen diferentes significados y funciones. Los detalles se pueden encontrar en la sección de ejemplos del documento oficial.

Aviso de declaración

"Notificación" se refiere a cuándo ejecutar la lógica AOP que definimos. Spring proporciona varias notificaciones:

  • @Antes de
  • @Después de regresar
  • @AfterThrowing
  • @After, su esencia es AfterFinally
  • @Alrededor

Todos deberían saber lo que significa el nombre. Entre ellos, @Around contiene todas las funciones anteriores, que es más potente y flexible de usar.

Una definición completa de AOP se ve así:

@Aspect
@Component
 public class MyAspect {
    
        
 
      @Pointcut("within(com.example.springbase.dao..*)")    
      private void myPointcut() {
    
    }    

    @Before("myPointcut()")    
    public void before() {
    
            
            System.out.println("before...");  
       }
}

Cabe señalar que "la anotación @Component aquí debe agregarse, de lo contrario Spring no escaneará automáticamente esta clase", entonces el aspecto, el punto de acceso y la notificación que definió no serán válidos.

Puede haber múltiples puntos de corte y múltiples notificaciones en un aspecto, y un punto de corte también puede ser utilizado por múltiples notificaciones.

¿Qué AOP implementa Spring?

Mencionamos AspectJ anteriormente. AspectJ usa tejido en tiempo de compilación y carga de clases, mientras que Spring AOP usa "tejido en tiempo de ejecución". Si utiliza tejido en tiempo de ejecución, debe utilizar la tecnología "proxy dinámico".

Hablemos primero de agentes dinámicos. AOP es en realidad una aplicación del "modo de agente" en el patrón de diseño, entonces, ¿qué es el modo de agente? Tomemos un ejemplo muy común, es decir, nivelación del juego.

El maestro de nivelación de poder del juego recogió el dinero del tirano local, abordó la cuenta del tirano local y logró ganar una racha hasta el rey más fuerte, luego completó la transacción y se retiró. Los compañeros y oponentes en el juego, incluso el oficial del juego, no sabían que se trataba de una nivelación de poder, pensaban que era el propio tirano local, elogiaban en privado las habilidades del tirano local y satisfacían la vanidad del tirano local. . .

En pocas palabras, el modelo de agencia es "envolver el objeto original para proporcionar algunas capacidades adicionales", pero es "insensible al exterior" y no sabe ni le importa si el objeto está siendo proxy.

La diferencia entre un proxy estático y un proxy dinámico es que el proxy estático ya ha escrito el tipo de proxy, y un proxy solo puede representar un tipo. El proxy dinámico es diferente: un proxy puede representar varios tipos. Tomemos como ejemplo la nivelación de potencia del juego. El agente estático puede ser el juego de nivelación de potencia que solo puede alcanzar el nivel de potencia LOL. Y agencia dinámica, esta nivelación de poder puede subir de nivel todos los juegos, ya sea que pueda jugarlo en la primera escucha.

Spring usa dos formas de implementar un proxy dinámico en la capa inferior, una es el proxy dinámico que viene con Java y la otra es CGLib. Si es un objeto proxy generado por el proxy dinámico JDK, Debug puede ver JdkDynamicAopProxy, y si es un objeto generado por CGLib, puede ver EnhancerBySpringCGLIB.

¿Qué método usa Spring específicamente? Hay muchos artículos en Internet que el comportamiento predeterminado de Spring para generar objetos proxy es: si su Bean tiene una interfaz correspondiente, use un proxy dinámico basado en JDK, de lo contrario use CGLIB. Pero esto en realidad no es exacto. Spring usa la siguiente configuración para controlarlo. Si esta configuración es falsa, es la lógica que mencionamos anteriormente. Y si esta configuración es verdadera, todos los beans que quieran usar AOP usan el proxy CGLIB, independientemente de si tiene una interfaz o no. Si usamos la última versión de SpringBoot, este valor es verdadero por defecto.

spring.aop.proxy-target-class=true

Así que ahora "si usa SpringBoot, nuestros objetos proxy AOP se generan con CGLIB".

¿Cuál es la diferencia entre el proxy dinámico JDK y CGLib?

Los principios de implementación de los dos son diferentes. El proxy dinámico JDK se implementa en base a la reflexión de Java, mientras que el proxy dinámico CGLIB se implementa en base a la modificación del bytecode y la generación de subclases. La capa inferior es la biblioteca de código abierto asm.

Ambos tienen algunas restricciones. Proxy dinámico JDK, Bean debe tener una interfaz, CGLIB no puede usar como proxy clases o métodos finales.

¿Qué métodos se pueden utilizar por proxy?

Si está utilizando un proxy dinámico JDK, solo se pueden usar los métodos públicos. Si utiliza CGLIB, todos los métodos se pueden utilizar como proxy, excepto los métodos privados. (Por supuesto, a excepción de los métodos finales).
Otra pregunta interesante es: "Si dos métodos están en la misma clase, no se delegará un método si se llama al otro". Solo cuando un bean llama al método de otro bean, pasará por el proxy.
Las dos características anteriores también explican por qué a veces su @Transactional no tiene efecto:

  • No tiene efecto en métodos privados
  • No tiene efecto en el método final.
  • Llamar a métodos en la misma clase no tiene efecto

¿Cuándo se generó el objeto proxy?

Entendemos cómo se generan los Spring Beans. Cuando Spring comience, llamará al método getBean para completar la inicialización del Bean. En getBan, después de inicializar el Bean, se llamará al BeanPostProcessor del Bean. Este código se puede encontrar mediante el método getBean Debug. No entraré en detalles sobre el proceso de depuración aquí, pongamos una captura de pantalla de la pila de llamadas.

Inserte la descripción de la imagen aquí
Como puede ver en Debug, uno de los BeanPostProcessor es de tipo AnnotationAwareAspectJAutoProxyCreator. Si continúa con Debug, puede ver que el objeto proxy finalmente se genera usando el método getProxy () de la clase CglibAopProxy.

Inserte la descripción de la imagen aquí

¿Qué debo hacer si el mismo método se ha enviado varias veces?

Un método puede ser proxy varias veces. Spring AOP no solo se basa en el modelo proxy, sino que también utiliza el modelo "interceptor". Este interceptor, un poco como un interceptor web, envuelve el objeto objetivo capa tras capa para formar una cadena de interceptores. ¿Cómo se determina su orden?
En nuestro análisis de código fuente anterior, hay una rama, la lógica es eliminar todas las "notificaciones" del objeto proxy actual y luego ordenarlas. El código está en el método de la clase AspectJAwareAdvisorAutoProxyCreator. Pila de llamadas:

Inserte la descripción de la imagen aquí
Este método primero elimina todas las notificaciones y luego les agrega un AspectJPrecedenceComparator. Este Comparador eliminará la prioridad definida por la anotación @Order del Bean donde se encuentra la notificación, y ordenará de acuerdo con esta prioridad. De hecho, a veces usamos esta anotación cuando usamos otros Beans.
Entonces, si declara múltiples notificaciones a un método, puede usar la anotación @Order para definir la prioridad de estas múltiples notificaciones. Cuanto menor sea el valor definido por @Order, el interceptor correspondiente a la notificación definida en su interior estará en la capa exterior de la cadena de llamadas.

Tenga en cuenta que si hay varias notificaciones definidas en la misma clase de aspecto, se ordenarán según el orden de declaración del método.

¿Qué pasa con AOP y las dependencias circulares?

Es posible que haya encontrado o oído hablar de las dependencias circulares de Spring. Spring usa el "caché de tres niveles" para resolver la dependencia circular de Bean, pero es posible que muchas personas no sepan por qué se usa el caché de tres niveles. De hecho, esto también está relacionado con AOP.

Si no hay AOP, Spring puede resolver el problema de la dependencia circular utilizando el caché de segundo nivel. Si se utiliza la caché de segundo nivel, en el caso de AOP, lo que se inyecta en otros Beans no es el objeto proxy final, sino el objeto de destino original.

Porque Spring tiene una definición de ciclo de vida para el Bean, y el objeto proxy se genera cuando se ejecuta el postprocesador después de que se inicializa el Bean. Por lo tanto, no es posible generar directamente objetos proxy en la caché secundaria y ponerlos en la caché.

¿Cuáles son las desventajas de usar AOP?

AOP no es una panacea y existen algunas desventajas al usar AOP. Personalmente, creo que el mayor inconveniente es "hacer que el código sea menos legible", porque no es una llamada explícita, por lo que es muy probable que la persona que se hará cargo del código en el futuro no sepa que este método es proxy de AOP.

El autor se ha encontrado con un proyecto antes, utilizando AOP para realizar el control de permisos, pero este control de permisos no es un simple acceso, sino para verificar algunos campos en la base de datos, como el estado y la lógica compleja. juicio. En este caso, si usa AOP para hacerlo, la legibilidad del código no es sólida y es más difícil solucionar problemas.

para resumir

La entrevista es inevitablemente ansiosa. Cualquiera que lo haya experimentado lo sabe. Pero si predice de antemano las preguntas que le hará el entrevistador y da una respuesta decente, será mucho más fácil.

Las respuestas a las preguntas de la entrevista están organizadas en notas de documentos. También clasifiqué algunos materiales de la entrevista y las últimas preguntas de la entrevista recopiladas por algunas grandes empresas en 2020 (todo organizado en documentos, una pequeña parte de las capturas de pantalla), si es necesario, puede hacer clic para ingresar la contraseña: csdn

Inserte la descripción de la imagen aquí

Inserte la descripción de la imagen aquí

Las respuestas a las preguntas de la entrevista anteriores están organizadas en notas de documentos. También clasifiqué algunos materiales de la entrevista y las últimas preguntas de la entrevista recopiladas por algunas grandes empresas en 2020 (todo organizado en documentos, una pequeña parte de las capturas de pantalla), si es necesario, puede hacer clic para ingresar la contraseña: csdn

¡Presta atención, no te pierdas! Si este artículo es útil para ti, ¡no olvides dar me gusta y apoyar!

Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_41770757/article/details/108477614
Recomendado
Clasificación