Mybatis 的插件运行原理

介绍

该笔记是在学习拉勾教育 Java 高薪训练营后,结合课程和老师的视频,自己跟踪源码后做的笔记。

Mybatis 插件运行原理

Mybatis 中的四大对象 Executor、ParameterHandler、ResultSetHandler、StatementHandler 都是代理对象。

在这里插入图片描述

如下代码,在创建时会调用 interceptorChain.pluginAll() 方法,遍历调用 plugin 方法判断是否返回目标对象本身,还是进行拦截返回代理对象。 如果拦截返回代理对象的话,之后调用时,会调用代理对象的拦截方法 intercept 进行拦截增强,从而实现调用插件。这与 RPC 客户端在调用接口原理类似,同样会对接口方法进行拦截,在拦截方法中实现一套远程调用逻辑。

    /**
     * 拦截器链
     */
    protected final InterceptorChain interceptorChain = new InterceptorChain();

    // 创建 ParameterHandler 对象
    public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
        // 创建 ParameterHandler 对象
        ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
        // 应用插件
        parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
        return parameterHandler;
    }

    // 创建 ResultSetHandler 对象
    public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
                                                ResultHandler resultHandler, BoundSql boundSql) {
        // 创建 DefaultResultSetHandler 对象
        ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
        // 应用插件
        resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
        return resultSetHandler;
    }

    // 创建 StatementHandler 对象
    public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        // 创建 RoutingStatementHandler 对象
        StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
        // 应用插件
        statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
        return statementHandler;
    }
    
    /**
     * 创建 Executor 对象
     */
    public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
        // ...
        // 应用插件
        executor = (Executor) interceptorChain.pluginAll(executor);
        return executor;
    }

自定义插件

Mybatis 在初始化时,将该自定义插件添加到拦截器链 InterceptorChain,当创建对象,比如 newExecutor 时会调用 pluginAll 方法。
  这里的目标对象 target 为 newExecutor,会遍历拦截链,找到针对 newExecutor 的自定义插件,返回其代理对象。

    public Object pluginAll(Object target) {
        for (Interceptor interceptor : interceptors) {
            target = interceptor.plugin(target);
        }
        return target;
    }
实现 Executor 的自定义插件(代理对象)

需要实现拦截器接口,使用注解 @Intercepts 来表示针对哪个对象进行拦截(返回其代理对象),以及该对象的方法和对应参数。如下会对 Executor 的 query 方法进行拦截,在调用该方法时,先调用代理对象的 intercept 方法。

@Intercepts({
    @Signature(
        type = Executor.class,
        method = "query",
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
    )
})
public class MyInterceptor implements Interceptor {
    
    @Override
    Object intercept(Invocation invocation) throws Throwable {}

    @Override
    Object plugin(Object target) {}

    @Override
    void setProperties(Properties properties) {}
}

reference

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值