MyBatis之插件原理

MyBatis 插件原理与自定义插件-应用场景分析(When)


还有公共字段统一赋值 


主要讲解 mybatis 插件的主要流程,其中主要包括动态代理和责任链的使用;

注册MyBatis插件方式(How)

在编写 mybatis 插件的时候,首先要实现 Interceptor 接口

1>在 mybatis-conf.xml 中添加插件


2>SpringBoot +MyBatis时候



mybatis 插件的拦截目标有四个,Executor、StatementHandler、ParameterHandler、ResultSetHandler

其次,我们必须实现Mybatis的Interceptor,还有此类需添加注解,例子:




intercept():执行拦截内容的地方

plugin():决定是否触发intercept()方法

setProperties():给自定义的拦截器传递我们配置的属性参数


以上是注册插件说明,而添加拦截链时机是以下:

在会话工厂创建会话sqlsession中一个步骤创建Executor执行器时候是调用Configuration里newExecutor(),其余都是创建执行器时候的子进程


原理分析--时序图

何时将拦截器放进Configuration的变量InterceptorChain?(蓝色框)


四大对象( Executor、StatementHandler、ParameterHandler、ResultSetHandler )何时被拦截器包装的?

上述已经说明清楚了(newExecutor()、newStatementHandler()、newParameterHandler()、newResultSetHandler())

四大对象( Executor、StatementHandler、ParameterHandler、ResultSetHandler )如何被拦截器包装( 插件植入的逻辑 )的?



细节:

Configuration使用的时候都是用动态代理将多个插件用责任链的方式添加的,最后返回的是一个代理对象;其责任链的添加过程如下


蓝色框实际调用了Plugin的wrap():

new Plugin(target, interceptor, signatureMap),生成代理对象是new Plugin(原有对象target, 带MyBatis插件 注解 并且实现插件逻辑的类 ,签名集合)

通过 getSignatureMap 方法反射取出对应的 Method 对象。结构如下:



在通过 getAllInterfaces 方法判断,目标对象是否有对应的方法,有就生成代理对象,没有就直接反对目标对象; 

这里所说的签名是指在编写插件的时候,指定的目标接口和方法(这里就指定了拦截 Executor 的具有相应方法的 update、query 方法),例如:


四大对象( Executor、StatementHandler、ParameterHandler、ResultSetHandler )被拦截器包装后的执行流程以及多个插件时候执行顺序:

包装后代理类是Plugin,Plugin 实现了 InvocationHandler 接口,因此它的 invoke 方法会拦截所有的方法调用。invoke 方法会对所拦截的方法进行检测,以决定是否执行插件逻辑。该方法的逻辑如下


invoke 方法的代码比较少,逻辑不难理解。首先,invoke 方法会检测被拦截方法是否配置在插件的 @Signature 注解中,若是,则执行插件逻辑,否则执行被拦截方法。插件逻辑封装在 intercept 中,该方法的参数类型为 Invocation。Invocation 主要用于存储目标类,方法以及方法参数列表。

注意:上述的执行逻辑里的signatureMap  interceptor  target都是在初始化Plugin时候已经赋值了。

自定义插件(慢查询):

执行顺序:

这里需要注意的是,添加的插件是有顺序的,因为在解析的时候是依次放入 ArrayList 里面,而调用的时候其顺序为:2 > 1 > target > 1 > 2。

(插件的顺序可能会影响执行的流程)更加细致的讲解可以参考 QueryInterceptor 规范

你可能感兴趣的:(MyBatis之插件原理)