Mybatis插件(拦截器)使用及源码追踪

 

Mybatis插件本质上就是一个拦截器,其应用代理模式,在方法级别上进行拦截。Mybatis插件可以用于SQL语句日志打印、权限控制、分页等功能。

 
MyBatis 允许使用插件来拦截的方法调用包括:
    Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
    ParameterHandler (getParameterObject, setParameters)
    ResultSetHandler (handleResultSets, handleOutputParameters)
    StatementHandler (prepare, parameterize, batch, update, query)
 
Mybatis插件的使用
 
使用Mybatis插件只需要两个步骤:1)创建拦截器实现类;2)在配置文件applicationContext.xml中注册拦截器。
 
1,创建拦截器实现类
package com.blueStarWei.interceptor;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.sql.Statement;

/**
* MyBatis 允许使用插件来拦截的方法调用包括:
*     Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
*     ParameterHandler (getParameterObject, setParameters)
*     ResultSetHandler (handleResultSets, handleOutputParameters)
*     StatementHandler (prepare, parameterize, batch, update, query)
*
*  拦截器顺序:
*       Executor -> ParameterHandler -> StatementHandler -> ResultSetHandler
*
*/
@Intercepts({
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class,Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = StatementHandler.class, method = "query", args = {Statement.class,ResultHandler.class})
})
public class SqlInterceptor implements Interceptor {

    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("------------------------bengin query-----------");
        Object target = invocation.getTarget();
        if(target instanceof StatementHandler) {
            StatementHandler handler = (StatementHandler) target;
            String sql = handler.getBoundSql().getSql();
            Object param = handler.getParameterHandler().getParameterObject();

            System.out.println("sql : "+sql.replace("?",param+""));
        }else if(target instanceof  Executor){
            Object[] args = invocation.getArgs();
            MappedStatement mappedStatement  = (MappedStatement) args[0];
            String methodName = mappedStatement.getId();
            System.out.println("method : "+methodName);

            BoundSql boundSql = mappedStatement.getBoundSql(args[1]);
            String sql = boundSql.getSql();
            Object param = boundSql.getParameterObject();
            System.out.println("sql : "+sql.replace("?",param+""));
        }
        Object result = invocation.proceed();
        System.out.println("result : "+result);
        System.out.println("------------------------bengin end-----------");
        return result;
    }
}

 

2,配置applicationContext.xml

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="datasource"/>
    <!--    指定*Mapper.xml位置-->
    <property name="mapperLocations" value="classpath:mapper/*.xml" />
    <!--注册Mybatis插件-->
    <property name="plugins"  >
      <bean class="com.blueStarWei.interceptor.SqlInterceptor" />
    </property>
</bean>

 

Mybatis插件原理

 

Mybatis插件采用的是代理模式+责任链模式,具体原理可以查看代理模式增强之路(代理+责任链模式)

 

Mybatis插件源码追踪

 

1, 服务启动阶段

在创建SqlSessionFactory的时候,注册拦截器,即:将拦截器添加到集合(interceptorChain)中。

 

创建执行处理器(Executor、StatementHandler、ParameterHandler、ResultSetHandler)并返回代理对象;

 

 

深入追踪pluginAll()源码:该方法会遍历集合(interceptors),调用每个interceptor的plugin(target)方法,对代理元封装,生成包含非业务逻辑的代理对象:

 

 

 

 

 

2,运行(CRUD)阶段

调用自定义拦截器的intercept()方法,执行自定义的逻辑

 

 

posted @ 2020-12-13 21:36  blue星空  阅读(551)  评论(0编辑  收藏  举报