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()方法,执行自定义的逻辑
更多内容,请访问:http://www.cnblogs.com/BlueStarWei