Principio del mecanismo de complemento de Mybatis

En Mybatis existe un poderoso mecanismo que nos permite invadir rápidamente las operaciones subyacentes de Mybatis para expandir las funciones de Mybatis, este es el mecanismo plug-in, y también podemos llamarlo mecanismo interceptor de Mybatis.

1. Principios básicos

En el sistema de arquitectura Mybatis, hay cuatro componentes principales (objetos), a saber , Executor, StatementHandler, ParameterHandler y ResultSetHandler . Cuando leemos el código fuente subyacente de Mybatis, podemos encontrar fácilmente que se llama a un método interceptor.plugin al crear estos cuatro componentes principales en Mybatis. Por lo tanto, nuestro complemento solo puede apuntar a estos cuatro objetos. Como sugiere el nombre, interceptor significa interceptor en chino. Cuando se trata de interceptor, podemos pensar fácilmente que su función es mejorar la lógica de un método antes o después de que se ejecute . En realidad, hay un poco de AOP aquí ( Programación de aspectos) gusto. En cuanto al mecanismo de complemento de Mybatis, su implementación es la programación de aspectos implementada por el mecanismo de proxy dinámico de jdk, que genera un objeto proxy para nuestros cuatro objetos principales, mejorando así la lógica de nuestros cuatro objetos principales para ejecutar los métodos correspondientes. .

2. Uso básico del complemento

Aquí hay una breve charla sobre cómo se usa nuestro complemento.

resultado de la operación:

De esta manera, el Intercepor está equipado, y la lógica del método de intercepción en el interior se ejecutará cuando el Ejecutor ejecute el método de consulta.

3. Implementación del principio subyacente del complemento

¿Por qué configuramos como en la figura anterior para permitir que nuestro complemento genere objetos proxy para los cuatro componentes principales de modo que pueda ejecutar la lógica mejorada del método de intercepción en el interior? Y se puede encontrar que el registro impreso "clase objetivo interceptada" imprime los cuatro objetos principales. Echemos un vistazo al código fuente para entenderlo.

En primer lugar, echemos un vistazo a las operaciones que realiza el complemento después de que se crea uno de los cuatro componentes principales. Tomemos Executor como ejemplo para ingresar el método de inicialización de Executor.

La lógica de inicialización del ejecutor se crea en el proceso de creación de SqlSession, por lo que llegamos a una determinada parte del código fuente al crear SqlSession

Para el análisis del proceso de creación de SqlSession en Mybatis, puede volver atrás y ver:

Análisis del principio de Mybatis (dos) el proceso de creación de SqlSession

Hay un método interceptorChain.pluginAll (ejecutor) ejecutado aquí. Eche un vistazo más de cerca a este método. Cuando creamos un objeto Executor, pasamos este objeto a este método, y luego nos devolvemos el objeto Executor. Supongo que debería ser Este objeto está empaquetado, podemos hacer clic en este método para ver

Inside es obtener cada Interceptor y luego llamar al método de complemento del interceptor. Este método toma nuestro objeto Executor y nos lo devuelve después de la ejecución. Así que este método es un método para empaquetar nuestros cuatro objetos principales. , Y como dijimos antes, el núcleo del mecanismo de complemento es generar un proxy dinámico para el objeto de destino, por lo que cuando implementamos nuestro interceptor, necesitamos obtener la clase de destino en el método de complemento y generar un proxy dinámico para la clase de destino El objeto luego regresó.

En este punto, nuestro objetivo es muy claro, es decir, generar un proxy dinámico para la clase objetivo y devolverlo en el método de complemento del Interceptor personalizado, luego ahora volvemos al método de complemento de nuestro Interceptor personalizado

Se puede ver que el objeto de proxy dinámico de la clase de destino debe crearse dentro, y un método Plugin.wrap (destino, esto) se llama directamente aquí, y la clase de destino y su propio objeto se pasan. Luego ingresamos este método para echar un vistazo, y directamente No es fácil comprender el código fuente, así que depurémoslo directamente.

Aquí encontramos un getSignatureMap. En primer lugar, nos sentimos un poco familiares por el nombre, ¿verdad? La palabra firma parece haber sido escrita en alguna parte, sí, en realidad escribimos esta anotación en nuestra clase personalizada Interceptor, y este método obtendrá todas las anotaciones @Signature que escribimos en Interceptor ¿Información? Echemos un vistazo más de cerca a este método

 Se puede encontrar que este método es consistente con nuestra suposición, que consiste en analizar la información de las anotaciones que escribimos. Entonces seguiremos buscando

Descubrimos que obtuvimos el objeto de clase de la clase de destino (la clase de destino aquí son los cuatro objetos principales), y luego pasamos el objeto de clase y el mapa devuelto anteriormente a un método getAllInterfaces, y el nombre debería ser el objeto de clase de interfaz. Vamos a profundizar más.

 Finalmente, lo que se nos devuelve es una matriz de objetos de clase que contiene cuatro objetos principales.

Y si la longitud de la matriz no es mayor que 0, entonces significa que el objeto de destino no necesita ser interceptado, y el objeto de destino se devuelve directamente, y si es mayor que 0, significa que el objeto de destino debe ser interceptado y luego usar el mecanismo de proxy dinámico de jdk. Genere el objeto proxy correspondiente. Entonces, todo el método de envoltura se ejecuta con éxito. Así que aquí hay un resumen del método de ajuste: primero, este método analizará toda la información de anotación en nuestra clase Interceptor personalizada, y usará el valor del atributo type como clave para generar una colección de objetos Method del tipo correspondiente según el método y los valores del atributo args. Es el valor, y luego de acuerdo con este mapa para que coincida si hay una entrada con los cuatro objetos de clase de componentes como clave, si la hay, coloque el objeto de clase de interfaz implementado por el objeto de destino (es decir, uno de los cuatro componentes) en la matriz, y finalmente Juzgue si el tamaño de esta matriz es mayor que 0. Si es mayor que 0, significa que es necesario crear un objeto proxy dinámico para el objeto de destino en este momento; de lo contrario, el objeto de destino se puede devolver directamente.

Después de obtener el objeto de proxy del objeto de destino, todos los métodos del objeto de destino que se ejecutan posteriormente ejecutarán primero el método de invocación del objeto de proxy. Y la clase que pasamos arriba que implementa la interfaz InvocationHandler es la clase Plugin, ingresemos el método de invocación de esta clase para ver

Es posible que tenga una pregunta aquí, es decir, si el método actualmente ejecutado es el método que especificamos para interceptar, luego return interceptor.intercept (new Invocation (target, method, args)) se ejecuta, y puede ver que esto es un retorno Con el valor de retorno del método de intercepción del interceptor personalizado, sabemos que es necesario mejorar un método en el proxy dinámico, y luego se debe ejecutar el proxy original después de la mejora, es decir, se debe devolver method.invoke (target, args) El valor de retorno ejecutará el código original, por lo que el valor de retorno del método de intercepción anterior no podrá ejecutar la lógica del método original después de la mejora. De hecho, no es el caso. El valor de retorno final de nuestro método de intercepción es en realidad el valor de retorno del código method.invoke (target, args), porque finalmente llamamos al código invocation.proceed () en el método de intercepción, y en este código , Podemos echar un vistazo

De hecho, este código sigue siendo method.invoke (target, args), por lo que ejecutaremos la lógica del método original después de mejorar el método. 

Finalmente, resuma el principio del mecanismo de plug-in de Mybatis: el plug-in en realidad solo es efectivo para los cuatro objetos principales, porque es difícil de escribir en Mybatis. En el proceso de creación de los cuatro objetos principales, los objetos se lanzarán al plug-in para generar el correspondiente Objetos de proxy dinámico. El método de generar objetos de proxy dinámicos también se implementa en el método de complemento del complemento. Mybatis encapsula el método de envoltura de una clase de complementos para generar objetos de proxy dinámicos. El principio de este método es obtener primero el Interceptor que estamos personalizando. La información anotada por @Intercepts y @Signature en la clase se encapsula en un objeto de mapa con el valor del atributo type como clave, y la colección establecida de objetos Method del tipo correspondiente se genera de acuerdo con el método y los valores del atributo args como valor, y luego en este mapa Ni almacena en caché qué método de qué clase se interceptará y mejorará, y cuando se ejecute el método del objeto proxy, ingresará al método invoke.En el método invoke, determine si el método actualmente ejecutado está en el mapa. Si existe, ejecute el método mejorado (método de intercepción) si existe, y ejecute la lógica del método original si no existe. ¡Así que el núcleo del complemento es el mecanismo de proxy dinámico!

Supongo que te gusta

Origin blog.csdn.net/weixin_37689658/article/details/99686884
Recomendado
Clasificación